| Possible issue |
✅ Fix UDP event binding and window guard
Suggestion Impact:The commit changed event bindings from this._socket to socket for both 'error' and 'message' events, aligning with the suggestion.
code diff:
- this._socket.on('error', error => {
+ socket.on('error', error => {
if (!window.isDestroyed()) {
window.webContents.send('udpError', error);
}
});
- this._socket.on('message', (message, _rinfo) => {
+ socket.on('message', (message, _rinfo) => {
Correct the UDP connection logic by attaching event listeners to the correct
socket object and adding a guard to prevent calling methods on a non-window object.
js/main/udp.js [3-34]
const socket = dgram.createSocket('udp4');
const udp = {
_id: 1,
- _ip: false,
- _port: false,
- connect: function(ip, port, window = true) {
+ _ip: null,
+ _port: null,
+ connect: function(ip, port, window) {
return new Promise(resolve => {
try {
- socket.bind(port, () => {
+ socket.once('listening', () => {
this._ip = ip;
this._port = port;
+ resolve({ error: false, id: this._id++ });
});
- this._socket.on('error', error => {
- if (!window.isDestroyed()) {
+ socket.on('error', error => {
+ if (window && typeof window.isDestroyed === 'function' && !window.isDestroyed()) {
window.webContents.send('udpError', error);
}
});
- this._socket.on('message', (message, _rinfo) => {
- if (!window.isDestroyed()) {
+ socket.on('message', (message, _rinfo) => {
+ if (window && typeof window.isDestroyed === 'function' && !window.isDestroyed()) {
window.webContents.send('udpMessage', message);
}
});
- resolve({error: false, id: this._id++});
+
+ socket.bind(port);
} catch (err) {
- resolve ({error: true, errorMsg: err});
+ resolve({ error: true, errorMsg: err });
}
});
},
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 10
__
Why: The suggestion correctly identifies two critical bugs in the new udp.connect function that would cause it to fail at runtime and prevent any UDP communication.
| High
|
✅ Fix undefined handler target
Suggestion Impact:The Drag constructor was modified to pass arrow functions for handleDownEvent/handleDragEvent/handleMoveEvent/handleUpEvent instead of direct app method references, addressing the undefined handler issue. However, the handlers were wired to app.handle... within the arrow functions rather than to this methods, and the additional instance method definitions were not added. Some constructor property initializations remained, but comments were removed.
code diff:
- class Drag extends PointerInteraction{
+ class Drag extends PointerInteraction {
constructor() {
super ({
- handleDownEvent: app.handleDownEvent,
- handleDragEvent: app.handleDragEvent,
- handleMoveEvent: app.handleMoveEvent,
- handleUpEvent: app.handleUpEvent
+ handleDownEvent: (evt) => app.handleDownEvent(evt),
+ handleDragEvent: (evt) => app.handleDragEvent(evt),
+ handleMoveEvent: (evt) => app.handleMoveEvent(evt),
+ handleUpEvent: (evt) => app.handleUpEvent(evt)
});
- /**
- * @type {ol.Pixel}
- * @private
- */
this.coordinate_ = null;
-
- /**
- * @type {string|undefined}
- * @private
- */
this.cursor_ = 'pointer';
-
- /**
- * @type {Feature}
- * @private
- */
this.feature_ = null;
-
- /**
- * @type {string|undefined}
- * @private
- */
this.previousCursor_ = undefined;
}
- };
-
+ }
Fix a reference error in the Drag class constructor by correctly referencing event handlers. The app object's methods are not defined at the time of instantiation.
tabs/mission_control.js [2000-2014]
-class Drag extends PointerInteraction{
+class Drag extends PointerInteraction {
constructor() {
- super ({
- handleDownEvent: app.handleDownEvent,
- handleDragEvent: app.handleDragEvent,
- handleMoveEvent: app.handleMoveEvent,
- handleUpEvent: app.handleUpEvent
+ super({
+ handleDownEvent: (evt) => this.handleDownEvent(evt),
+ handleDragEvent: (evt) => this.handleDragEvent(evt),
+ handleMoveEvent: (evt) => this.handleMoveEvent(evt),
+ handleUpEvent: (evt) => this.handleUpEvent(evt),
});
+ this.coordinate_ = null;
+ this.cursor_ = 'pointer';
+ this.feature_ = null;
+ this.previousCursor_ = undefined;
+ }
- /**
- * @type {ol.Pixel}
- * @private
- */
- this.coordinate_ = null;
- ...
+ handleDownEvent(evt) {
+ return app.handleDownEvent(evt);
}
-};
+ handleDragEvent(evt) {
+ return app.handleDragEvent(evt);
+ }
+ handleMoveEvent(evt) {
+ return app.handleMoveEvent(evt);
+ }
+ handleUpEvent(evt) {
+ return app.handleUpEvent(evt);
+ }
+}
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 9
__
Why: The suggestion correctly identifies that app.handle... functions are undefined when new Drag() is called, which will cause a runtime error.
| High
|
✅ Correct OpenLayers Feature import
Suggestion Impact:The commit updated the import from 'ol/format/Feature' to 'ol/Feature', correcting the module source for Feature.
code diff:
-import Feature from 'ol/format/Feature';
+import Feature from 'ol/Feature';
Change the import for Feature from ol/format/Feature to ol/Feature.js to correctly import the feature constructor.
js/groundstation.js [13-175]
-import Feature from 'ol/format/Feature';
+import Feature from 'ol/Feature.js';
...
privateScope.cursorFeature = new Feature({
geometry: privateScope.cursorPosition
});
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 9
__
Why: This suggestion correctly identifies a critical bug where an incorrect module is imported, which would cause a runtime error when new Feature() is called.
| High
|
✅ Fix mismatched DOM id selector
Suggestion Impact:The commit updated the jQuery selectors from #armedicon to #armedIcon in both branches, matching the suggested fix.
code diff:
if (FC.isModeEnabled('ARM')) {
- $("#armedicon").removeClass('armed');
- $("#armedicon").addClass('armed-active');
+ $("#armedIcon").removeClass('armed');
+ $("#armedIcon").addClass('armed-active');
} else {
- $("#armedicon").removeClass('armed-active');
- $("#armedicon").addClass('armed');
+ $("#armedIcon").removeClass('armed-active');
+ $("#armedIcon").addClass('armed');
Fix the jQuery selector for the armed status icon by changing #armedicon to
#armedIcon to match the element's ID in the HTML.
js/periodicStatusUpdater.js [42-48]
if (FC.isModeEnabled('ARM')) {
- $("#armedicon").removeClass('armed');
- $("#armedicon").addClass('armed-active');
+ $("#armedIcon").removeClass('armed');
+ $("#armedIcon").addClass('armed-active');
} else {
- $("#armedicon").removeClass('armed-active');
- $("#armedicon").addClass('armed');
+ $("#armedIcon").removeClass('armed-active');
+ $("#armedIcon").addClass('armed');
}
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 9
__
Why: The suggestion correctly identifies a bug where the jQuery selector armedicon does not match the HTML element ID armedIcon, which would prevent the armed status icon from updating.
| High
|
✅ Normalize and validate icon key mapping
Suggestion Impact:The commit replaced the icons object initialization with Object.create(null), introduced an iconKey function, normalized dynamic imports to use the base filename, threw an error when icon URL is missing, and updated all icon accesses to use bracket notation with normalized keys.
code diff:
+const icons = Object.create(null)
+
////////////////////////////////////
//
// Tab mission control block
@@ -181,19 +183,26 @@
}
}
+function iconKey(filename) {
+ // drop extension, keep base name (e.g., "icon_RTH")
+ return filename.replace(/\.(png|svg)$/i, '');
+}
+
async function loadIcons() {
- for (const icon of iconNames) {
- const nameSplit = icon.split('.');
+ for (const fname of iconNames) {
// Vites packager needs a bit help
- var iconUrl;
- if (nameSplit[1] == 'png') {
- iconUrl = (await import(`./../images/icons/map/cf_${nameSplit[0]}.png?inline`)).default;
- } else if (nameSplit[1] == 'svg') {
- iconUrl = (await import(`./../images/icons/map/cf_${nameSplit[0]}.svg?inline`)).default;
- }
- if (iconUrl) {
- icons[nameSplit[0]] = iconUrl;
- }
+ const base = iconKey(fname);
+ const ext = fname.split('.').pop();
+ let iconUrl;
+ if (ext === 'png') {
+ iconUrl = (await import(`./../images/icons/map/cf_${base}.png?inline`)).default;
+ } else if (ext === 'svg') {
+ iconUrl = (await import(`./../images/icons/map/cf_${base}.svg?inline`)).default;
+ }
+ if (!iconUrl) {
+ throw new Error(`Missing icon URL for ${fname}`);
+ }
+ icons[base] = iconUrl;
}
}
@@ -281,7 +290,7 @@
anchor: [0.5, 0.5],
opacity: 1,
scale: 0.6,
- src: icons.icon_mission_airplane
+ src: icons['icon_mission_airplane']
}))
});
@@ -308,7 +317,7 @@
anchor: [0.5, 1.0],
opacity: 1,
scale: 0.5,
- src: icons.icon_RTH
+ src: icons['icon_RTH']
}))
});
@@ -621,7 +630,7 @@
anchor: [0.5, 1],
opacity: 1,
scale: 0.5,
- src: safehome.isUsed() ? icons.icon_safehome_used : icons.icon_safehome
+ src: safehome.isUsed() ? icons['icon_safehome_used'] : icons['icon_safehome']
})),
text: new Text(({
text: String(Number(safehome.getNumber())+1),
@@ -841,7 +850,7 @@
anchor: [0.5, 1],
opacity: 1,
scale: 0.5,
- src: geozone.getType() == GeozoneType.EXCULSIVE ? icons.icon_geozone_excl : icons.icon_geozone_incl
+ src: geozone.getType() == GeozoneType.EXCULSIVE ? icons['icon_geozone_excl'] : icons['icon_geozone_incl']
})),
text: new Text(({
text: String(number + 1),
@@ -1178,7 +1187,7 @@
anchor: [0.5, 1],
opacity: 1,
scale: 0.5,
- src: icons.icon_home
+ src: icons['icon_home']
})),
});
}
@@ -1641,7 +1650,7 @@
featureArrow.setStyle(
new Style({
image: new Icon({
- src: icons.icon_arrow,
+ src: icons['icon_arrow'],
scale: 0.3,
anchor: [0.5, 0.5],
rotateWithView: true,
@@ -1997,7 +2006,7 @@
// Drag behavior definition
//////////////////////////////////////////////////////////////////////////////////////////////
- class Drag extends PointerInteraction{
+ class Drag extends PointerInteraction {
constructor() {
super ({
handleDownEvent: app.handleDownEvent,
@@ -2006,32 +2015,12 @@
handleUpEvent: app.handleUpEvent
});
- /**
- * @type {ol.Pixel}
- * @private
- */
this.coordinate_ = null;
-
- /**
- * @type {string|undefined}
- * @private
- */
this.cursor_ = 'pointer';
-
- /**
- * @type {Feature}
- * @private
- */
this.feature_ = null;
-
- /**
- * @type {string|undefined}
- * @private
- */
this.previousCursor_ = undefined;
}
- };
-
+ }
app.ConvertCentimetersToMeters = function (val) {
return parseInt(val) / 100;
@@ -2044,7 +2033,7 @@
var button = document.createElement('button');
button.innerHTML = ' ';
- button.style = `background: url("${icons.settings_white}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
+ button.style = `background: url("${icons['settings_white']}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
var handleShowSettings = function () {
@@ -2073,7 +2062,7 @@
var button = document.createElement('button');
button.innerHTML = ' ';
- button.style = `background: url("${icons.icon_safehome_white}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
+ button.style = `background: url("${icons['icon_safehome_white']}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
var handleShowSafehome = function () {
$('#missionPlannerSafehome').fadeIn(300);
@@ -2105,7 +2094,7 @@
var button = document.createElement('button');
button.innerHTML = ' ';
- button.style = `background: url("${icons.icon_geozone_white}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
+ button.style = `background: url("${icons['icon_geozone_white']}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
var handleShowGeozoneSettings = function () {
$('#missionPlannerGeozones').fadeIn(300);
@@ -2138,7 +2127,7 @@
var button = document.createElement('button');
button.innerHTML = ' ';
- button.style = `background: url("${icons.icon_elevation_white}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
+ button.style = `background: url("${icons['icon_elevation_white']}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
var handleShowSettings = function () {
$('#missionPlannerHome').fadeIn(300);
@@ -2171,7 +2160,7 @@
var button = document.createElement('button');
button.innerHTML = ' ';
- button.style = `background: url("${icons.icon_multimission_white}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
+ button.style = `background: url("${icons['icon_multimission_white']}") no-repeat 1px -1px;background-color: rgba(0,60,136,.5);`;
Normalize the icon key mapping to prevent broken image URLs. The dynamic import path is inconsistent with how icons are accessed, and the iconNames array contains a duplicate entry.
tabs/mission_control.js [70-198]
const iconNames = [
'icon_mission_airplane.png',
- ...
- 'icon_multimission_white.svg'
+ 'icon_RTH.png',
+ 'icon_safehome.png',
+ 'icon_safehome_used.png',
+ 'icon_geozone_excl.png',
+ 'icon_geozone_incl.png',
+ 'icon_home.png',
+ 'icon_position_edit.png',
+ 'icon_position_head.png',
+ 'icon_position_LDG_edit.png',
+ 'icon_position_LDG.png',
+ 'icon_position_PH_edit.png',
+ 'icon_position_PH.png',
+ 'icon_position_POI.png',
+ 'icon_position_POI_edit.png',
+ 'icon_position_WP_edit.png',
+ 'icon_position_WP.png',
+ 'icon_arrow.png',
+ 'settings_white.svg',
+ 'icon_safehome_white.svg',
+ 'icon_geozone_white.svg',
+ 'icon_elevation_white.svg',
+ 'icon_multimission_white.svg'
];
-var icons = {};
-...
+const icons = Object.create(null);
+
+function iconKey(filename) {
+ // drop extension, keep base name (e.g., "icon_RTH")
+ return filename.replace(/\.(png|svg)$/i, '');
+}
+
async function loadIcons() {
- for (const icon of iconNames) {
- const nameSplit = icon.split('.');
- // Vites packager needs a bit help
- var iconUrl;
- if (nameSplit[1] == 'png') {
- iconUrl = (await import(`./../images/icons/map/cf_${nameSplit[0]}.png?inline`)).default;
- } else if (nameSplit[1] == 'svg') {
- iconUrl = (await import(`./../images/icons/map/cf_${nameSplit[0]}.svg?inline`)).default;
+ for (const fname of iconNames) {
+ const base = iconKey(fname);
+ const ext = fname.split('.').pop();
+ let iconUrl;
+ if (ext === 'png') {
+ iconUrl = (await import(`./../images/icons/map/cf_${base}.png?inline`)).default;
+ } else if (ext === 'svg') {
+ iconUrl = (await import(`./../images/icons/map/cf_${base}.svg?inline`)).default;
}
- if (iconUrl) {
- icons[nameSplit[0]] = iconUrl;
+ if (!iconUrl) {
+ throw new Error(`Missing icon URL for ${fname}`);
}
+ icons[base] = iconUrl;
}
}
+// usage examples adjusted:
+// src: icons['icon_RTH']
+// src: icons['icon_position' + (suffixes...)]
+
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 8
__
Why: The suggestion correctly points out that the dynamic import path cf_${nameSplit[0]} is inconsistent with how icons are accessed later, which will lead to broken image URLs.
| Medium
|
✅ Fix async HTML/icon load order
Suggestion Impact:The function load_html was converted to async, awaited the HTML import and loadIcons(), and then called GUI.load with process_html, matching the suggested change.
code diff:
+ async function load_html() {
+ const { default: html } = await import('./gps.html?raw');
+ await loadIcons();
+ GUI.load(html, Settings.processHtml(process_html));
Refactor load_html to be an async function. Await the completion of loadIcons() before calling GUI.load to ensure icons are loaded before process_html is executed.
tabs/gps.js [117-119]
-function load_html() {
- import('./gps.html?raw').then(({default: html}) => GUI.load(html, Settings.processHtml(loadIcons().then(process_html))));
+async function load_html() {
+ const { default: html } = await import('./gps.html?raw');
+ await loadIcons();
+ GUI.load(html, Settings.processHtml(process_html));
}
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 8
__
Why: The suggestion correctly identifies a critical race condition where process_html could execute before loadIcons completes, leading to runtime errors.
| Medium
|
✅ Prevent variable shadowing
Suggestion Impact:The commit renamed the inner 'model' to 'modelScene' and updated usages, addressing variable shadowing. It also changed the loader call to use 'modelUrl', partially aligning with the suggestion, though the destructuring change isn't shown here.
code diff:
- loader.load(model, (obj) => {
- const model = obj.scene;
+ loader.load(modelUrl, (obj) => {
+ const modelScene = obj.scene;
const scaleFactor = 15;
- model.scale.set(scaleFactor, scaleFactor, scaleFactor);
- modelWrapper.add(model);
+ modelScene.scale.set(scaleFactor, scaleFactor, scaleFactor);
+ modelWrapper.add(modelScene);
Rename the model variable inside the loader.load callback to avoid shadowing the
model variable from the outer scope, which holds the imported URL.
tabs/magnetometer.js [741-746]
-import(`./../resources/models/model_${model_file}.gltf`).then(({default: model}) => {
-loader.load(model, (obj) => {
- const model = obj.scene;
+import(`./../resources/models/model_${model_file}.gltf`).then(({ default: model: modelUrl }) => {
+ loader.load(modelUrl, (obj) => {
+ const modelScene = obj.scene;
const scaleFactor = 15;
- model.scale.set(scaleFactor, scaleFactor, scaleFactor);
- modelWrapper.add(model);
+ modelScene.scale.set(scaleFactor, scaleFactor, scaleFactor);
+ modelWrapper.add(modelScene);
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 4
__
Why: The suggestion correctly identifies variable shadowing which is poor practice, but the proposed improved_code contains a syntax error in the destructuring assignment.
| Low
|
✅ Remove duplicate API property
Suggestion Impact:The commit removed the duplicated storeSet entry, leaving a single definition.
code diff:
- storeSet: (key, value) => ipcRenderer.send('storeSet', key, value),
storeSet: (key, value) => ipcRenderer.send('storeSet', key, value),
Remove the duplicate storeSet property from the object exposed via contextBridge to improve code quality and prevent potential future errors.
js/main/preload.js [4-10]
contextBridge.exposeInMainWorld('electronAPI', {
listSerialDevices: () => ipcRenderer.invoke('listSerialDevices'),
storeGet: (key, defaultValue) => ipcRenderer.sendSync('storeGet', key, defaultValue),
storeSet: (key, value) => ipcRenderer.send('storeSet', key, value),
- storeSet: (key, value) => ipcRenderer.send('storeSet', key, value),
storeDelete: (key) => ipcRenderer.send('storeDelete', key),
- ...
+ appGetPath: (name) => ipcRenderer.sendSync('appGetPath', name),
+ appGetVersion: () => ipcRenderer.sendSync('appGetVersion'),
+ appGetLocale: () => ipcRenderer.sendSync('appGetLocale'),
+ showOpenDialog: (options) => ipcRenderer.invoke('dialog.showOpenDialog', options),
+ showSaveDialog: (options) => ipcRenderer.invoke('dialog.showSaveDialog', options),
+ alertDialog: (message) => ipcRenderer.sendSync('dialog.alert', message),
+ confirmDialog: (message) => ipcRenderer.sendSync('dialog.confirm', message),
+ tcpConnect: (host, port) => ipcRenderer.invoke('tcpConnect', host, port),
+ tcpClose: () => ipcRenderer.send('tcpClose'),
+ tcpSend: (data) => ipcRenderer.invoke('tcpSend', data),
+ onTcpError: (callback) => ipcRenderer.on('tcpError', (_event, error) => callback(error)),
+ onTcpData: (callback) => ipcRenderer.on('tcpData', (_event, data) => callback(data)),
+ onTcpEnd: (callback) => ipcRenderer.on('tcpEnd', (_event) => callback()),
+ serialConnect: (path, options) => ipcRenderer.invoke('serialConnect', path, options),
+ serialClose: () => ipcRenderer.invoke('serialClose'),
+ serialSend: (data) => ipcRenderer.invoke('serialSend', data),
+ onSerialError: (callback) => ipcRenderer.on('serialError', (_event, error) => callback(error)),
+ onSerialData: (callback) => ipcRenderer.on('serialData', (_event, data) => callback(data)),
+ onSerialClose: (callback) => ipcRenderer.on('serialClose', (_event) => callback()),
+ udpConnect: (ip, port) => ipcRenderer.invoke('udpConnect', ip, port),
+ udpClose: () => ipcRenderer.invoke('udpClose'),
+ udpSend: (data) => ipcRenderer.invoke('udpSend', data),
+ onUdpError: (callback) => ipcRenderer.on('udpError', (_event, error) => callback(error)),
+ onUdpMessage: (callback) => ipcRenderer.on('udpMessage', (_event, data) => callback(data)),
+ writeFile: (filename, data) => ipcRenderer.invoke('writeFile', filename, data),
+ readFile: (filename, encoding = 'utf8') => ipcRenderer.invoke('readFile', filename, encoding),
+ rm: (path) => ipcRenderer.invoke('rm', path),
+ chmod: (path, mode) => ipcRenderer.invoke('chmod', path, mode),
+ startChildProcess: (command, args, opts) => ipcRenderer.send('startChildProcess', command, args, opts),
+ killChildProcess: () => ipcRenderer.send('killChildProcess'),
+ onChildProcessStdout: (callback) => ipcRenderer.on('onChildProcessStdout', (_event, data) => callback(data)),
+ onChildProcessStderr: (callback) => ipcRenderer.on('onChildProcessStderr', (_event, data) => callback(data)),
+ onChildProcessError: (callback) => ipcRenderer.on('onChildProcessError', (_event, error) => callback(error)),
});
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 3
__
Why: The suggestion correctly identifies a duplicate key storeSet which, while not causing a functional bug here, is a code quality issue that should be fixed.
| Low
|
| Security |
✅ Sanitize user-provided profile name
Suggestion Impact:The commit implements input trimming, adds HTML-escaping via safeText when appending the option, renames eeprom variable, and applies some stylistic changes. This addresses the XSS concern.
code diff:
- smalltalk.prompt(i18n.getMessage('sitlNewProfile'), i18n.getMessage('sitlEnterName')).then(name => {
+ smalltalk.prompt(i18n.getMessage('sitlNewProfile'), i18n.getMessage('sitlEnterName')).then(rawName => {
+ const name = (rawName || '').trim();
if (!name)
return;
- if (profiles.find(e => { return e.name == name })) {
+ if (profiles.find(e => e.name == name )) {
dialog.alert(i18n.getMessage('sitlProfileExists'));
return;
}
- var eerpromName = name.replace(/[^a-z0-9]/gi, '_').toLowerCase() + ".bin";
+ const safeText = $('<div>').text(name).html(); // escape
+ const eepromName = name.replace(/[^a-z0-9]/gi, '_').toLowerCase() + '.bin';;
var profile = {
name: name,
- sim: "RealFlight",
+ sim: 'RealFlight',
isStdProfile: false,
simEnabled: false,
- eepromFileName: eerpromName,
+ eepromFileName: eepromName,
port: 49001,
- ip: "127.0.0.1",
+ ip: '127.0.0.1',
useImu: false,
channelMap: [ 1, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0],
useSerialReceiver: true,
serialPort: serialPorts_e.val(),
serialUart: 3,
- serialProtocol: "SBus",
+ serialProtocol: 'SBus',
baudRate: false,
stopBits: false,
parity: false
- }
+ };
profiles.push(profile);
- profiles_e.append(`<option value="${name}">${name}</option>`)
+ profiles_e.append(`<option value="${safeText}">${safeText}</option>`)
profiles_e.val(name);
updateCurrentProfile();
saveProfiles();
- }).catch(() => {} );
+ }).catch(() => {});
Sanitize the user-provided profile name before inserting it into the DOM to prevent a potential cross-site scripting (XSS) vulnerability.
tabs/sitl.js [258-292]
profileNewBtn_e.on('click', function () {
- smalltalk.prompt(i18n.getMessage('sitlNewProfile'), i18n.getMessage('sitlEnterName')).then(name => {
- if (!name)
- return;
+ smalltalk.prompt(i18n.getMessage('sitlNewProfile'), i18n.getMessage('sitlEnterName')).then(rawName => {
+ const name = (rawName || '').trim();
+ if (!name) return;
- if (profiles.find(e => { return e.name == name })) {
+ if (profiles.find(e => e.name === name)) {
dialog.alert(i18n.getMessage('sitlProfileExists'));
return;
}
- var eerpromName = name.replace(/[^a-z0-9]/gi, '_').toLowerCase() + ".bin";
- var profile = {
- name: name,
- sim: "RealFlight",
+ const safeText = $('<div>').text(name).html(); // escape
+ const eepromName = name.replace(/[^a-z0-9]/gi, '_').toLowerCase() + '.bin';
+ const profile = {
+ name,
+ sim: 'RealFlight',
isStdProfile: false,
simEnabled: false,
- eepromFileName: eerpromName,
+ eepromFileName: eepromName,
port: 49001,
- ip: "127.0.0.1",
+ ip: '127.0.0.1',
useImu: false,
- channelMap: [ 1, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ channelMap: [1, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0],
useSerialReceiver: true,
serialPort: serialPorts_e.val(),
serialUart: 3,
- serialProtocol: "SBus",
+ serialProtocol: 'SBus',
baudRate: false,
stopBits: false,
parity: false
- }
+ };
profiles.push(profile);
- profiles_e.append(`<option value="${name}">${name}</option>`)
+ profiles_e.append(`<option value="${safeText}">${safeText}</option>`);
profiles_e.val(name);
updateCurrentProfile();
saveProfiles();
- }).catch(() => {} );
+ }).catch(() => {});
});
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 8
__
Why: The suggestion correctly identifies a cross-site scripting (XSS) vulnerability by using unescaped user input to construct HTML, which is a critical security issue.
| Medium
|
|
| |