Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Data from "../../modules/data.js"
import Data from "../../modules/data.js"
import EventHandler from "../../modules/event-handler.js"

const selectCell = (el, index) => {
Expand Down Expand Up @@ -73,7 +73,7 @@ export function init(id) {
e.preventDefault()
selectCell(el, index - 1)
}
else if (e.key === 'Delete' || e.key === 'Tab' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
else if (e.composed || e.key === 'Delete' || e.key === 'Tab' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition of e.composed to this condition is incorrect. The composed property is a boolean that indicates whether the event can bubble across the shadow DOM boundary, not whether the event is from IME composition. This will allow all composed events (which is most standard events) to bypass validation, potentially allowing invalid input.

If the intent is to allow IME composition input, this is already handled by the separate compositionend event handler at line 25. The e.composed check should be removed.

Suggested change
else if (e.composed || e.key === 'Delete' || e.key === 'Tab' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
else if (e.key === 'Delete' || e.key === 'Tab' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {

Copilot uses AI. Check for mistakes.

}
else {
Expand All @@ -89,6 +89,26 @@ export function init(id) {
}
}
})

EventHandler.on(c, 'paste', e => {
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new 'paste' event handler is not being cleaned up in the dispose function (lines 115-125). This creates a memory leak as the event listener will persist after the component is disposed.

The dispose function should include:

EventHandler.off(c, 'paste')

Copilot uses AI. Check for mistakes.
e.preventDefault();
const raw = (e.clipboardData || window.clipboardData)?.getData('text') ?? '';
if (!raw) {
return;
}
const parts = raw.replace(/[^\d.]/g, '').split('.').filter(p => p.length);
const cells = el.querySelectorAll(".ipv4-cell");
let pos = 0;
parts.forEach(p => {
if (pos > 3) {
return;
}
const num = Math.max(0, Math.min(255, parseInt(p, 10) || 0));
cells[pos].value = num.toString();
ip.prevValues[pos] = cells[pos].value;
pos++;
});
Comment on lines +99 to +110
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex /[^\d.]/g allows multiple consecutive dots and doesn't validate IP address format. For example, "192...168" would be parsed as ["192", "168"], silently ignoring the malformed input. Consider adding validation or using a more robust parsing approach that validates IP address format before processing.

Suggested change
const parts = raw.replace(/[^\d.]/g, '').split('.').filter(p => p.length);
const cells = el.querySelectorAll(".ipv4-cell");
let pos = 0;
parts.forEach(p => {
if (pos > 3) {
return;
}
const num = Math.max(0, Math.min(255, parseInt(p, 10) || 0));
cells[pos].value = num.toString();
ip.prevValues[pos] = cells[pos].value;
pos++;
});
// Validate IPv4 address format: four octets, each 0-255, separated by dots
const ipv4Regex = /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$/;
if (!ipv4Regex.test(raw.trim())) {
// Invalid IP address format; ignore paste
return;
}
const parts = raw.trim().split('.');
const cells = el.querySelectorAll(".ipv4-cell");
for (let pos = 0; pos < 4; pos++) {
cells[pos].value = parts[pos];
ip.prevValues[pos] = cells[pos].value;
}

Copilot uses AI. Check for mistakes.
});
Comment on lines +93 to +111
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The paste event handler always starts pasting from position 0, ignoring which cell the user is actually focused on. When a user pastes "192.168" while focused on the second cell, it overwrites the first two cells instead of filling from the second cell onward.

Consider using the index parameter (available in the forEach scope) to start pasting from the currently focused cell:

let pos = index;
parts.forEach(p => {
    if (pos > 3) {
        return;
    }
    const num = Math.max(0, Math.min(255, parseInt(p, 10) || 0));
    cells[pos].value = num.toString();
    ip.prevValues[pos] = cells[pos].value;
    pos++;
});

Copilot uses AI. Check for mistakes.
})
}

Expand Down