| 2 |
raymond |
1 |
<!DOCTYPE html>
|
|
|
2 |
<html lang="en">
|
|
|
3 |
<head>
|
|
|
4 |
<meta charset="UTF-8">
|
|
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
6 |
<title>Login</title>
|
|
|
7 |
<style>
|
|
|
8 |
#about {color:lightgray};
|
|
|
9 |
body {background-color: #f5f5f5; font-family: Arial, sans-serif;}
|
|
|
10 |
header, footer {padding: 10px; background-color: #024c5b; color: #fff; width: 50%; text-align: center;}
|
|
|
11 |
header {margin-top: 40px;}
|
|
|
12 |
label {display: block; margin: 5px;}
|
|
|
13 |
input[type="text"], input[type="password"], input[type="email"] {width: 80%; padding: 8px; border: 1px solid #ddd; border-radius: 3px;}
|
|
|
14 |
button[type="submit"] {margin-top: 20px; width: 50%; min-width: 60px; padding: 10px; background-color: #607D8B; color: white; border: none; cursor: pointer;}
|
|
|
15 |
button[type="submit"]:hover, .nav {background-color: #16729F;}
|
|
|
16 |
.container {display: flex; flex-direction: column; align-items: center; min-height: 100vh;}
|
|
|
17 |
.custom-container {padding: 10px; width: 50%; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); background-color: #ffffff;}
|
|
|
18 |
.content {padding: 20px; display: flex; flex-direction: column;}
|
|
|
19 |
.center {text-align: center};
|
|
|
20 |
</style>
|
|
|
21 |
</head>
|
|
|
22 |
<body>
|
|
|
23 |
<div class="container">
|
|
|
24 |
<header>
|
|
|
25 |
<h1>ESP32 RFID Logs - Login</h1>
|
|
|
26 |
</header>
|
|
|
27 |
<div class="custom-container">
|
|
|
28 |
<div class="content">
|
|
|
29 |
<form id="loginForm" class="center">
|
|
|
30 |
<div>
|
|
|
31 |
<label for="username">Username:</label>
|
|
|
32 |
<input type="text" id="username" name="username" required>
|
|
|
33 |
</div>
|
|
|
34 |
<div>
|
|
|
35 |
<label for="password">Password:</label>
|
|
|
36 |
<input type="password" id="password" name="password" required>
|
|
|
37 |
</div>
|
|
|
38 |
<button type="submit">Login</button>
|
|
|
39 |
</form>
|
|
|
40 |
</div>
|
|
|
41 |
</div>
|
|
|
42 |
<footer class="footer">
|
|
|
43 |
<div class="has-text-centered">
|
|
|
44 |
<p> RFID Log © 2025. All rights reserved.</p>
|
|
|
45 |
<a id=about target=_blank rel=noopener href="https://github.com/cotestatnt/async-esp-fs-webserver">Created with https://github.com/cotestatnt/async-esp-fs-webserver</a>
|
|
|
46 |
</div>
|
|
|
47 |
</footer>
|
|
|
48 |
</div>
|
|
|
49 |
|
|
|
50 |
<script>
|
|
|
51 |
// To avoid sharing plain text between client and server,
|
|
|
52 |
// send SHA256 of password input text (based on https://geraintluff.github.io/sha256/)
|
|
|
53 |
function sha256(ascii) {
|
|
|
54 |
var rightRotate = (value, amount) => (value >>> amount) | (value << (32 - amount));
|
|
|
55 |
var mathPow = Math.pow, maxWord = mathPow(2, 32), lengthProperty = 'length', result = '', words = [], asciiBitLength = ascii[lengthProperty] * 8;
|
|
|
56 |
var hash = sha256.h = sha256.h || [], k = sha256.k = sha256.k || [], primeCounter = k[lengthProperty];
|
|
|
57 |
var isComposite = {};
|
|
|
58 |
for (var candidate = 2; primeCounter < 64; candidate++) {
|
|
|
59 |
if (!isComposite[candidate]) {
|
|
|
60 |
for (i = 0; i < 313; i += candidate) isComposite[i] = candidate;
|
|
|
61 |
hash[primeCounter] = (mathPow(candidate, .5) * maxWord) | 0;
|
|
|
62 |
k[primeCounter++] = (mathPow(candidate, 1 / 3) * maxWord) | 0;
|
|
|
63 |
}
|
|
|
64 |
}
|
|
|
65 |
ascii += '\x80';
|
|
|
66 |
while (ascii[lengthProperty] % 64 - 56) ascii += '\x00';
|
|
|
67 |
for (i = 0; i < ascii[lengthProperty]; i++) {
|
|
|
68 |
j = ascii.charCodeAt(i);
|
|
|
69 |
if (j >> 8) return;
|
|
|
70 |
words[i >> 2] |= j << ((3 - i) % 4) * 8;
|
|
|
71 |
}
|
|
|
72 |
words[words[lengthProperty]] = ((asciiBitLength / maxWord) | 0);
|
|
|
73 |
words[words[lengthProperty]] = (asciiBitLength);
|
|
|
74 |
for (j = 0; j < words[lengthProperty];) {
|
|
|
75 |
var w = words.slice(j, j += 16);
|
|
|
76 |
var oldHash = hash.slice(0, 8);
|
|
|
77 |
for (i = 0; i < 64; i++) {
|
|
|
78 |
var i2 = i + j, w15 = w[i - 15], w2 = w[i - 2];
|
|
|
79 |
var a = hash[0], e = hash[4];
|
|
|
80 |
var temp1 = hash[7] + (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) + ((e & hash[5]) ^ ((~e) & hash[6])) + k[i] +
|
|
|
81 |
(w[i] = (i < 16) ? w[i] : (w[i - 16] + (rightRotate(w15, 7) ^ rightRotate(w15, 18) ^ (w15 >>> 3)) + w[i - 7] +
|
|
|
82 |
(rightRotate(w2, 17) ^ rightRotate(w2, 19) ^ (w2 >>> 10))) | 0);
|
|
|
83 |
|
|
|
84 |
var temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) + ((a & hash[1]) ^ (a & hash[2]) ^ (hash[1] & hash[2]));
|
|
|
85 |
hash = [(temp1 + temp2) | 0].concat(hash);
|
|
|
86 |
hash[4] = (hash[4] + temp1) | 0;
|
|
|
87 |
}
|
|
|
88 |
for (i = 0; i < 8; i++) hash[i] = (hash[i] + oldHash[i]) | 0;
|
|
|
89 |
}
|
|
|
90 |
for (i = 0; i < 8; i++)
|
|
|
91 |
for (j = 3; j + 1; j--)
|
|
|
92 |
result += ((hash[i] >> (j * 8)) & 255).toString(16).padStart(2, '0');
|
|
|
93 |
return result;
|
|
|
94 |
};
|
|
|
95 |
|
|
|
96 |
document.getElementById('loginForm').addEventListener('submit', async function(event) {
|
|
|
97 |
event.preventDefault();
|
|
|
98 |
const username = document.getElementById('username').value;
|
|
|
99 |
const password = document.getElementById('password').value;
|
|
|
100 |
const hash = sha256(password);
|
|
|
101 |
|
|
|
102 |
// 1. Effettua il login con POST
|
|
|
103 |
const postResponse = await fetch('/rfid', {
|
|
|
104 |
method: 'POST',
|
|
|
105 |
body: new URLSearchParams({ username, hash }),
|
|
|
106 |
});
|
|
|
107 |
|
|
|
108 |
if (!postResponse.ok) {
|
|
|
109 |
alert("Login fallito");
|
|
|
110 |
return;
|
|
|
111 |
}
|
|
|
112 |
|
|
|
113 |
// 2. Se il POST ha successo, invia una richiesta PUT
|
|
|
114 |
const putResponse = await fetch('/rfid', {
|
|
|
115 |
method: 'PUT',
|
|
|
116 |
body: new URLSearchParams({ username, hash }),
|
|
|
117 |
});
|
|
|
118 |
|
|
|
119 |
if (putResponse.ok) {
|
|
|
120 |
// 3. Estrai l'HTML dalla risposta e sostituisci l'intero documento
|
|
|
121 |
const html = await putResponse.text();
|
|
|
122 |
|
|
|
123 |
// Apri un nuovo documento e scrivi l'HTML ricevuto
|
|
|
124 |
document.open();
|
|
|
125 |
document.write(html);
|
|
|
126 |
document.close(); // Forza l'esecuzione degli script
|
|
|
127 |
// history.pushState({}, "", "/rfid");
|
|
|
128 |
} else {
|
|
|
129 |
alert("Errore durante l'operazione PUT");
|
|
|
130 |
}
|
|
|
131 |
});
|
|
|
132 |
</script>
|
|
|
133 |
</body>
|
|
|
134 |
</html>
|