-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
313 lines (266 loc) · 10.1 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
<!DOCTYPE html>
<html>
<head>
<title>Pidgeon</title>
<link rel="icon" href="https://raw.githubusercontent.com/StringManolo/pidgeon/0b146558f562cf4d1028b74c72a2b2c5a2ee980c/img/pidgeon.webp">
<style>
body {
font-family: Arial, sans-serif;
}
h1 {
text-align: center;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.button-container {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
button {
padding: 8px 16px;
font-size: 16px;
background-color: #7E69E2;
color: white;
border: none;
border-radius: 4%;
cursor: pointer;
margin: 0.5px;
}
.input-container {
margin-bottom: 10px;
}
label {
font-weight: bold;
}
input[type='text'],
input[type='file'] {
padding: 8px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
box-sizing: border-box;
}
#logOutput {
width: 100%;
height: 300px;
overflow-y: scroll;
background-color: black;
color: white;
font-family: monospace;
padding: 10px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/3.0.0/jsencrypt.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.24.0/axios.min.js"></script>
</head>
<body>
<div class="container">
<h1>Pidgeon</h1>
<div class="button-container">
<button onclick="createUser()">Create User</button>
<button onclick="getUserList()">Get User List</button>
<button onclick="findUser()">Find User</button>
<button onclick="sendMessage()">Send Message</button>
<button onclick="decryptInbox()">Decrypt Inbox</button>
<button onclick="deleteInbox()">Delete Inbox</button>
</div>
<div class="input-container">
<label for="privateKeyInput">Private Key:</label>
<input type="file" id="privateKeyInput" onchange="handlePrivateKeyChange()" accept=".pem" />
</div>
<div class="input-container">
<label for="endpointInput">Server Endpoint:</label>
<input type="text" id="endpointInput" value="https://publicpidgeon.glitch.me/" />
<button onclick="updateEndpoint()">Update Endpoint</button>
</div>
<div id="logOutput"></div>
</div>
<script>
let publicKey;
let privateKey;
let serverEndpoint = 'https://publicpidgeon.glitch.me/';
function logToDiv(message) {
const logDiv = document.getElementById('logOutput');
logDiv.innerText += message + '\n';
logDiv.scrollTop = logDiv.scrollHeight; // Desplazar hasta el final
}
// Actualizar el endpoint del servidor
function updateEndpoint() {
const endpointInput = document.getElementById('endpointInput');
serverEndpoint = endpointInput.value;
logToDiv('Server endpoint updated: ' + serverEndpoint);
}
// Crear un nuevo usuario con alias y generar par de claves
async function createUser() {
const alias = prompt('Enter the user alias:');
if (!alias) return;
// Verificar si el usuario ya existe en la base de datos
try {
await axios.get(`${serverEndpoint}/users/${alias}`);
logToDiv('The user already exists in the database.');
return;
} catch (error) {
// El usuario no existe en la base de datos
}
// Verificar si el usuario ya tiene una clave privada
if (await privateKeyExists(alias)) {
logToDiv(`The user already has a private key but doesn't exist in the database. Remove the key:\n\nrm "./pidgeon_${alias}_privKey.pem"`);
return;
}
const { publicKey, privateKey } = generateRSAKeyPair();
try {
await axios.post(`${serverEndpoint}/users`, { alias, pubKey: publicKey });
logToDiv('User created successfully');
logToDiv('Private key generated:\n' + privateKey);
downloadPrivateKey(privateKey, `pidgeon_${alias}_privKey.pem`);
} catch (error) {
logToDiv('Error creating the user: ' + error.response?.data.error);
}
}
// Enviar un mensaje a un usuario
async function sendMessage() {
const userId = prompt('Enter the user ID:');
if (!userId) return;
const sender = prompt('Enter the sender:');
if (!sender) return;
const content = prompt('Enter the message content:');
if (!content) return;
try {
const response = await axios.get(`${serverEndpoint}/users/${userId}`);
const user = response.data;
const encryptedMessage = encryptMessage(content, user.pubKey);
const messageData = {
sender,
content: encryptedMessage, };
await axios.post(`${serverEndpoint}/users/${userId}/inbox`, messageData);
logToDiv('Message sent successfully');
} catch (error) {
logToDiv('Error sending the message: ' + error);
}
}
// Decryptar la bandeja de entrada de un usuario
async function decryptInbox() {
const userId = prompt('Enter the user ID:');
if (!userId) return;
try {
const response = await axios.get(`${serverEndpoint}/users/${userId}/inbox`);
const inbox = response.data;
if (!privateKey) {
logToDiv('No private key available.');
return;
}
// Decryptar cada mensaje en la bandeja de entrada
const decryptedInbox = inbox.map((message) => {
const decryptedContent = decryptMessage(message.content, privateKey);
return { ...message, content: decryptedContent };
});
logToDiv('Decrypted inbox: ' + JSON.stringify(decryptedInbox));
} catch (error) {
logToDiv('Error decrypting the inbox: ' + error.response?.data.error);
}
}
// Manejar el evento de cambio de la entrada de clave privada
function handlePrivateKeyChange() {
const file = document.getElementById('privateKeyInput').files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (e) {
privateKey = e.target.result;
logToDiv('Private key loaded from file:\n' + privateKey);
};
reader.readAsText(file);
}
// Verificar si existe el archivo de clave privada
async function privateKeyExists(alias) {
try {
await axios.get(`${serverEndpoint}/users/${alias}`);
return true; // El usuario existe en la base de datos
} catch (error) {
return false; // El usuario no existe en la base de datos
}
}
// Generar un par de claves RSA
function generateRSAKeyPair() {
const encrypt = new JSEncrypt({ default_key_size: 2048 });
publicKey = encrypt.getPublicKey();
privateKey = encrypt.getPrivateKey();
logToDiv('Key pair generated:');
logToDiv('Public Key: ' + publicKey);
logToDiv('Private Key: ' + privateKey);
return { publicKey, privateKey };
}
// Cifrar un mensaje con la clave pública
function encryptMessage(message, publicKey) {
const encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
return encrypt.encrypt(message);
}
// Decryptar un mensaje con la clave privada
function decryptMessage(encryptedMessage, privateKey) {
const decrypt = new JSEncrypt();
decrypt.setPrivateKey(privateKey);
return decrypt.decrypt(encryptedMessage);
}
// Descargar la clave privada como un archivo PEM
function downloadPrivateKey(key, fileName) {
const element = document.createElement('a');
element.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(key);
element.download = fileName || 'private_key.pem';
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
// Obtener la lista de usuarios
async function getUserList() {
try {
const response = await axios.get(`${serverEndpoint}/users`);
logToDiv('List of users: ' + JSON.stringify(response.data));
} catch (error) {
logToDiv('Error getting the list of users: ' + error.response?.data.error);
}
}
// Encontrar un usuario por alias o pubKey
async function findUser() {
const userId = prompt('Enter the user ID:');
if (!userId) return;
try {
const response = await axios.get(`${serverEndpoint}/users/${userId}`);
logToDiv('User found: ' + JSON.stringify(response.data));
} catch (error) {
logToDiv('Error finding the user: ' + error.response?.data.error);
}
}
// Borrar la bandeja de entrada de un usuario
async function deleteInbox() {
const userId = prompt('Enter the user ID:');
if (!userId) return;
try {
const response = await axios.get(`${serverEndpoint}/users/${userId}/inbox/deleteKey`);
const { encryptedKey } = response.data;
if (!privateKey) {
logToDiv('No private key available.');
return;
}
const decrypt = new JSEncrypt();
decrypt.setPrivateKey(privateKey);
const decryptedKey = decrypt.decrypt(encryptedKey);
logToDiv('[DEBUG] Decrypted key: ' + decryptedKey);
const deleteResponse = await axios.delete(`${serverEndpoint}/users/${userId}/inbox`, { data: { deleteKey: decryptedKey } });
if (deleteResponse.data.success) {
logToDiv('Inbox emptied successfully');
} else {
logToDiv('Failed to empty the inbox');
}
} catch (error) {
logToDiv('Error deleting the inbox: ' + error.response?.data.error);
}
}
</script>
</body>
</html>