|
@@ -0,0 +1,328 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="en">
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
|
+ <title>Magic Packet | ESPWoL</title>
|
|
|
+ <style>
|
|
|
+ body{
|
|
|
+ font-family: Arial, sans-serif;
|
|
|
+ color: #262626;
|
|
|
+ }
|
|
|
+ .box {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .wallpaper{
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ background-color: #ffffff;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ .main{
|
|
|
+ width: 480px;
|
|
|
+ height: calc(90vh - 2em);
|
|
|
+ padding: 1em;
|
|
|
+ -webkit-box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
|
|
|
+ -moz-box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
|
|
|
+ box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
|
|
|
+ border-radius: 0.6em;
|
|
|
+ border: 1px solid rgb(172, 172, 172);
|
|
|
+ position: relative;
|
|
|
+ background-color: white;
|
|
|
+ }
|
|
|
+
|
|
|
+ .divider{
|
|
|
+ width: calc(100% - 4em);
|
|
|
+ padding-top: 0.4em;
|
|
|
+ margin-bottom: 0.4em;
|
|
|
+ border-bottom: 1px solid rgb(226, 226, 226);
|
|
|
+ padding-right: 2em;
|
|
|
+ padding-left: 2em;
|
|
|
+ }
|
|
|
+
|
|
|
+ small{
|
|
|
+ color: rgb(59, 59, 59);
|
|
|
+ }
|
|
|
+
|
|
|
+ .codeblock{
|
|
|
+ padding: 0.6em;
|
|
|
+ background-color: #242424;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Properties Table */
|
|
|
+ .table_component {
|
|
|
+ overflow: auto;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table_component table {
|
|
|
+ border: 1px solid #dededf;
|
|
|
+ height: 100%;
|
|
|
+ width: 100%;
|
|
|
+ table-layout: fixed;
|
|
|
+ border-collapse: collapse;
|
|
|
+ border-spacing: 1px;
|
|
|
+ text-align: left;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table_component caption {
|
|
|
+ caption-side: top;
|
|
|
+ text-align: left;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table_component th {
|
|
|
+ border: 1px solid #dededf;
|
|
|
+ background-color: #eceff1;
|
|
|
+ color: #000000;
|
|
|
+ padding: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table_component td {
|
|
|
+ border: 1px solid #dededf;
|
|
|
+ background-color: #ffffff;
|
|
|
+ color: #000000;
|
|
|
+ padding: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* status blinker */
|
|
|
+ #statusBlinker{
|
|
|
+ position: absolute;
|
|
|
+ left: 1em;
|
|
|
+ bottom: 1em;
|
|
|
+ width: 1em;
|
|
|
+ height: 2px;
|
|
|
+ background-color: rgb(95, 95, 95);
|
|
|
+ }
|
|
|
+
|
|
|
+ #statusBlinker.interval{
|
|
|
+ background-color: rgb(235, 235, 235);
|
|
|
+ }
|
|
|
+
|
|
|
+ input[type=text] {
|
|
|
+ width: 100%;
|
|
|
+ padding: 6px 10px;
|
|
|
+ margin: 8px 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .themebtn{
|
|
|
+ padding: 0.6em;
|
|
|
+ padding-left: 1.2em;
|
|
|
+ padding-right: 1em;
|
|
|
+ background-color: #242424;
|
|
|
+ border-radius: 0.4em;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .themebtn.blue{
|
|
|
+ background-color: #466bb1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .themebtn.red{
|
|
|
+ background-color: #b14646;
|
|
|
+ }
|
|
|
+
|
|
|
+ .themebtn:hover{
|
|
|
+ opacity: 0.6;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+ <div class="wallpaper"></div>
|
|
|
+ <br>
|
|
|
+ <div class="box">
|
|
|
+ <div class="main">
|
|
|
+ <h2>✨ WoL Magic Packet</h2>
|
|
|
+ <p>Select a host below to send Wake-on-LAN magic packet for remote startup</p>
|
|
|
+ <div class="table_component" role="region" tabindex="0">
|
|
|
+ <table>
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th>Name</th>
|
|
|
+ <th>MAC Address</th>
|
|
|
+ <th>Action</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody id="storedMacList">
|
|
|
+ <tr>
|
|
|
+ <td>
|
|
|
+
|
|
|
+ </td>
|
|
|
+ <td>
|
|
|
+
|
|
|
+ </td>
|
|
|
+ <td>
|
|
|
+
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ <h3>🖥️ Add Computer </h3>
|
|
|
+ <p>You can add more computer MAC address to the list</p>
|
|
|
+ <p style="margin-bottom: 0;">Target name: </p>
|
|
|
+ <input id="nameInput" type="text">
|
|
|
+ <p style="margin-bottom: 0;">MAC Address: </p>
|
|
|
+ <input id="macInput" type="text">
|
|
|
+ <button class="themebtn" onclick="handleAddMacAddress();">Add MAC Address</button>
|
|
|
+ <br>
|
|
|
+ <div class="divider"></div>
|
|
|
+ <small>ESPWoL | Deisnged by tobychui 2023 - 2024</small>
|
|
|
+ <br><br>
|
|
|
+ <div><a href="/">Back</a></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <script>
|
|
|
+ let currentListOfMacs = [];
|
|
|
+
|
|
|
+ function initMacAddressList(){
|
|
|
+ fetch("/api/mem/read", {
|
|
|
+ method: "GET",
|
|
|
+ })
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error("Failed to read MAC address list");
|
|
|
+ }
|
|
|
+ return response.json();
|
|
|
+ }).then(data => {
|
|
|
+ let macTable = document.getElementById("storedMacList");
|
|
|
+ macTable.innerHTML = "";
|
|
|
+ currentListOfMacs = data;
|
|
|
+ if (data.length == 0){
|
|
|
+ //No devices
|
|
|
+ macTable.innerHTML = `<tr><td colspan="3">✔️ No stored MAC address</td></tr>`;
|
|
|
+ }else{
|
|
|
+ //Create a table
|
|
|
+ let newTable = "";
|
|
|
+ for(var i = 0; i < data.length; i++){
|
|
|
+ newTable += `<tr>
|
|
|
+ <td>
|
|
|
+ ${data[i].name}
|
|
|
+ </td>
|
|
|
+ <td style="overflow-wrap: break-word; word-break: break-word;">
|
|
|
+ ${data[i].mac}
|
|
|
+ </td>
|
|
|
+ <td>
|
|
|
+ <button class="themebtn blue" onclick="sendWoL('${data[i].mac}');">Wake</button>
|
|
|
+ <button class="themebtn red" onclick="delRecord('${data[i].mac}');">Delete</button>
|
|
|
+ </td>
|
|
|
+ </tr>`;
|
|
|
+ }
|
|
|
+ macTable.innerHTML = newTable;
|
|
|
+ }
|
|
|
+ console.log(data);
|
|
|
+ }).catch(error => {
|
|
|
+ let macTable = document.getElementById("storedMacList");
|
|
|
+ macTable.innerHTML = `<tr><td colspan="3">✔️ No stored MAC address</td></tr>`;
|
|
|
+ console.error("Error:", error);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ initMacAddressList();
|
|
|
+
|
|
|
+
|
|
|
+ function sendWoL(macaddr){
|
|
|
+ fetch("/api/wol?mac=" + macaddr, {
|
|
|
+ method: "GET",
|
|
|
+ })
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error("Failed to send WoL packet");
|
|
|
+ }
|
|
|
+
|
|
|
+ //ok! Reset the input fileds
|
|
|
+ alert("Wake on LAN packet sent!")
|
|
|
+ return;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ //Remove a record from the list
|
|
|
+ function delRecord(macaddr){
|
|
|
+ let newListOfMac = [];
|
|
|
+ currentListOfMacs.forEach(record => {
|
|
|
+ if (record.mac != macaddr){
|
|
|
+ newListOfMac.push(record);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ //save the new list to server
|
|
|
+ fetch("/api/mem/write?mac=" + JSON.stringify(newListOfMac), {
|
|
|
+ method: "POST",
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json"
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error("Failed to write MAC address list");
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ })
|
|
|
+ .then(data => {
|
|
|
+ initMacAddressList();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ function isValidMacAddress(macAddress) {
|
|
|
+ // MAC address pattern: XX:XX:XX:XX:XX:XX
|
|
|
+ // Where X is a hexadecimal digit (0-9, A-F)
|
|
|
+ var macRegex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
|
|
+ return macRegex.test(macAddress);
|
|
|
+ }
|
|
|
+
|
|
|
+ function handleAddMacAddress(){
|
|
|
+ let newName = document.getElementById("nameInput").value;
|
|
|
+ if (newName.trim() == ""){
|
|
|
+ alert("Target name is missing!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let newMacAddress = document.getElementById("macInput").value;
|
|
|
+ newMacAddress = newMacAddress.trim();
|
|
|
+ if (!isValidMacAddress(newMacAddress)){
|
|
|
+ alert("Mac address is invalid");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //Append the new name and mac to the list
|
|
|
+ currentListOfMacs.push({
|
|
|
+ "name":newName,
|
|
|
+ "mac":newMacAddress
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ fetch("/api/mem/write?mac=" + JSON.stringify(currentListOfMacs), {
|
|
|
+ method: "POST",
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json"
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error("Failed to write MAC address list");
|
|
|
+ }
|
|
|
+
|
|
|
+ //ok! Reset the input fileds
|
|
|
+ document.getElementById("nameInput").value = "";
|
|
|
+ document.getElementById("macInput").value = "";
|
|
|
+ return;
|
|
|
+ })
|
|
|
+ .then(data => {
|
|
|
+ initMacAddressList();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+</body>
|
|
|
+</html>
|