fix: harden Wake-on-LAN MAC handling

Normalize stored MAC addresses, avoid shell execution for ether-wake, handle missing WOL history gracefully, and improve the WOL menu display for named MAC entries.
This commit is contained in:
wenjie
2026-05-20 11:38:14 +08:00
parent 6ae742deed
commit 94749ea621
2 changed files with 208 additions and 95 deletions

View File

@@ -56,33 +56,37 @@ export const Wol = () => {
const isEdit = false;
const macList = rsp.data.macs
.filter((item: string) => item.trim() !== '')
.map((item: string) => item.trim())
.filter((item: string) => item !== '')
.map((item: string) => {
const parts = item.split(' ');
const isName = parts.length > 1;
const name = isName ? parts[1] : '';
const mac = parts[0];
const separator = item.search(/\s/);
const mac = separator === -1 ? item : item.slice(0, separator);
const name = separator === -1 ? '' : item.slice(separator).trim();
const isName = name !== '';
const isShow = !isName;
return { name, mac, isShow, isName, isEdit };
});
setMacList([]);
setMacList(macList);
});
}
function toggleShow(mac: string) {
setMacList(
macList.map((item) => (item.mac === mac ? { ...item, isShow: !item.isShow } : item))
setMacList((list) =>
list.map((item) => (item.mac === mac ? { ...item, isShow: !item.isShow } : item))
);
}
function editMac(mac: string, isEdit: boolean) {
setMacList(macList.map((item) => (item.mac === mac ? { ...item, isEdit: !isEdit } : item)));
setMacList((list) =>
list.map((item) => (item.mac === mac ? { ...item, isEdit: !isEdit } : item))
);
}
async function setMacName(e: React.KeyboardEvent<HTMLInputElement>, mac: string) {
const value: string = e.currentTarget.value;
const value = e.currentTarget.value.trim();
if (!value) return;
const rsp = await setWolMacName(mac, value);
if (rsp.code !== 0) {
console.log(rsp.msg);
@@ -102,7 +106,7 @@ export const Wol = () => {
function wake(mac?: string) {
if (status === 'loading') return;
const value = mac ? mac : input;
const value = (mac ? mac : input).trim();
if (!value) return;
setStatus('loading');
@@ -123,6 +127,7 @@ export const Wol = () => {
})
.catch(() => {
setStatus('failed');
setLog(t('auth.error'));
});
}
@@ -134,15 +139,20 @@ export const Wol = () => {
<Divider style={{ margin: '10px 0 10px 0' }} />
<div className="pb-1 text-neutral-500">{t('wol.input')}</div>
<div className="flex items-center space-x-1">
<Input ref={inputRef} value={input} onChange={handleChange} onPressEnter={() => wake()} />
<Button type="primary" onClick={() => wake()}>
{t('wol.ok')}
</Button>
</div>
<div className="w-full space-y-1 py-3">
<div className="flex items-center space-x-1">
<Input
ref={inputRef}
value={input}
placeholder={t('wol.input')}
onChange={handleChange}
onPressEnter={() => wake()}
/>
<Button type="primary" onClick={() => wake()}>
{t('wol.ok')}
</Button>
</div>
<div className={clsx('py-2')}>
{status && (
<div
className={clsx(
@@ -155,58 +165,60 @@ export const Wol = () => {
)}
</div>
<List
itemLayout="horizontal"
locale={{ emptyText: ' ' }}
dataSource={macList}
renderItem={(item) => (
<List.Item className="flex w-full items-center justify-between">
<div className="h-[24px] max-w-[200px]">
{item.isEdit ? (
<Input
onFocus={() => setIsKeyboardEnable(false)}
onBlur={() => setIsKeyboardEnable(true)}
defaultValue={item.name}
onPressEnter={(e) => setMacName(e, item.mac)}
/>
) : item.isShow ? (
item.mac
) : (
item.name
)}
</div>
{macList.length > 0 && (
<List
itemLayout="horizontal"
dataSource={macList}
renderItem={(item) => (
<List.Item className="flex w-full items-center justify-between">
<div className="h-[24px] max-w-[200px]">
{item.isEdit ? (
<Input
placeholder={item.mac}
onFocus={() => setIsKeyboardEnable(false)}
onBlur={() => setIsKeyboardEnable(true)}
defaultValue={item.name}
onPressEnter={(e) => setMacName(e, item.mac)}
/>
) : item.isShow ? (
item.mac
) : (
item.name
)}
</div>
<div className="flex items-center space-x-1">
{item.isName && (
<div className="flex items-center space-x-1">
{item.isName && (
<div
className="text-500 flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded hover:bg-neutral-700/80"
onClick={() => toggleShow(item.mac)}
>
{item.isShow ? <EyeClosed size={16} /> : <Eye size={16} />}
</div>
)}
<div
className="text-500 flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded hover:bg-neutral-700/80"
onClick={() => toggleShow(item.mac)}
className="text-500 flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded hover:bg-neutral-700"
onClick={() => editMac(item.mac, item.isEdit)}
>
{item.isShow ? <EyeClosed size={16} /> : <Eye size={16} />}
<Pencil size={16} />
</div>
<div
className="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-green-500 hover:bg-neutral-700/80"
onClick={() => wake(item.mac)}
>
<SendIcon size={16} />
</div>
<div
className="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-red-500 hover:bg-neutral-700"
onClick={() => deleteMac(item.mac)}
>
<Trash2Icon size={16} />
</div>
)}
<div
className="text-500 flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded hover:bg-neutral-700"
onClick={() => editMac(item.mac, item.isEdit)}
>
<Pencil size={16} />
</div>
<div
className="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-green-500 hover:bg-neutral-700/80"
onClick={() => wake(item.mac)}
>
<SendIcon size={16} />
</div>
<div
className="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-red-500 hover:bg-neutral-700"
onClick={() => deleteMac(item.mac)}
>
<Trash2Icon size={16} />
</div>
</div>
</List.Item>
)}
/>
</List.Item>
)}
/>
)}
</div>
);