-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprofil.html
More file actions
254 lines (228 loc) · 15.8 KB
/
profil.html
File metadata and controls
254 lines (228 loc) · 15.8 KB
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Culture.Support</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
body { font-family: 'Inter', sans-serif; }
.custom-scrollbar::-webkit-scrollbar { width: 6px; }
.custom-scrollbar::-webkit-scrollbar-track { background: transparent; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
</style>
</head>
<body class="bg-slate-50 text-slate-900 min-h-screen">
<div id="app" class="max-w-6xl mx-auto px-4 py-6 md:py-10">
<!-- Header -->
<header class="flex flex-col md:flex-row md:items-center justify-between mb-8 gap-6">
<div>
<div class="flex items-center gap-3">
<div class="bg-blue-600 p-2 rounded-lg text-white">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10"/></svg>
</div>
<h1 class="text-2xl md:text-3xl font-extrabold tracking-tight">WireGuard Generator</h1>
</div>
<p class="text-slate-500 mt-2 text-sm md:text-base">Secure Hub-and-Spoke VPN Configuration Utility</p>
</div>
<div class="flex flex-wrap gap-3">
<button onclick="downloadServerConf()" class="flex-1 md:flex-none bg-slate-900 text-white px-5 py-2.5 rounded-xl font-semibold flex items-center justify-center gap-2 hover:bg-slate-800 transition-all shadow-sm active:scale-95">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Export Server
</button>
<button onclick="addClient()" class="flex-1 md:flex-none bg-blue-600 text-white px-5 py-2.5 rounded-xl font-semibold flex items-center justify-center gap-2 hover:bg-blue-700 transition-all shadow-sm active:scale-95">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Add Client
</button>
</div>
</header>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
<!-- Left Column: Server Settings -->
<aside class="lg:col-span-4 space-y-6">
<div class="bg-white p-6 rounded-2xl shadow-sm border border-slate-200">
<div class="flex items-center gap-3 mb-6 border-b border-slate-100 pb-4">
<svg class="text-blue-600" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg>
<h2 class="font-bold text-lg">Server Configuration</h2>
</div>
<div class="space-y-5">
<div class="group">
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1.5 ml-1">Public Endpoint</label>
<input type="text" id="serverHost" value="vpn.example.com" oninput="updateServer()" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 outline-none transition-all font-medium">
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1.5 ml-1">Listen Port</label>
<input type="number" id="serverPort" value="51820" oninput="updateServer()" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 outline-none transition-all">
</div>
<div>
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1.5 ml-1">Tunnel IP</label>
<input type="text" id="serverIp" value="10.8.0.1/24" oninput="updateServer()" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 outline-none transition-all">
</div>
</div>
<div>
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1.5 ml-1">Public Key</label>
<div class="flex items-center gap-2">
<input type="text" id="serverPub" readonly class="w-full px-4 py-2 bg-slate-100 border border-slate-200 rounded-xl text-xs font-mono text-slate-500 overflow-hidden text-ellipsis cursor-not-allowed">
<button onclick="copyToClipboard('serverPub')" class="p-2 text-slate-400 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
</button>
</div>
</div>
</div>
</div>
<!-- Technical Fact Card -->
<div class="bg-blue-900 text-blue-100 p-6 rounded-2xl shadow-sm overflow-hidden relative">
<svg class="absolute -right-4 -bottom-4 text-blue-800/50" width="120" height="120" fill="currentColor" viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10"/></svg>
<h3 class="font-bold mb-2 flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
Security Logic
</h3>
<p class="text-xs leading-relaxed opacity-80">
WireGuard utilizes Cryptokey Routing. To an unauthorized observer, your server port is silent (dropped packets) until a packet signed with a valid peer key arrives.
</p>
</div>
</aside>
<!-- Right Column: Clients List -->
<main class="lg:col-span-8">
<div id="clientList" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Dynamic Content -->
</div>
<div id="emptyState" class="hidden flex flex-col items-center justify-center bg-white border-2 border-dashed border-slate-200 rounded-3xl p-16 text-center">
<div class="bg-slate-50 p-6 rounded-full mb-4">
<svg class="text-slate-300" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="16" y1="11" x2="22" y2="11"/></svg>
</div>
<h3 class="text-xl font-bold text-slate-700">No Peers Defined</h3>
<p class="text-slate-400 max-w-xs mt-2">Add clients to generate unique private/public key pairs and specific interface configs.</p>
</div>
</main>
</div>
</div>
<script>
let server = {
hostname: '95.55.22.35',
port: '5450',
ip: '10.8.0.1/24',
privateKey: '',
publicKey: '',
dns: '1.1.1.1'
};
let clients = [];
// Key generation (Simulated via Web Crypto for portability)
function generateKeyPair() {
const array = new Uint8Array(32);
window.crypto.getRandomValues(array);
const priv = btoa(String.fromCharCode(...array));
// Simulated Pub derivation (Reversed for visual distinction in demo)
const pub = btoa(String.fromCharCode(...array.reverse()));
return { priv, pub };
}
function init() {
const keys = generateKeyPair();
server.privateKey = keys.priv;
server.publicKey = keys.pub;
document.getElementById('serverPub').value = keys.pub;
renderClients();
}
function updateServer() {
server.hostname = document.getElementById('serverHost').value;
server.port = document.getElementById('serverPort').value;
server.ip = document.getElementById('serverIp').value;
}
function addClient() {
const keys = generateKeyPair();
const id = Date.now();
const index = clients.length + 2;
clients.push({
id: id,
name: `Device-${index}`,
ip: `10.8.0.${index}/32`,
privateKey: keys.priv,
publicKey: keys.pub,
keepalive: 25
});
renderClients();
}
function removeClient(id) {
clients = clients.filter(c => c.id !== id);
renderClients();
}
function copyToClipboard(elementId) {
const el = document.getElementById(elementId);
el.select();
document.execCommand('copy');
// Visual feedback
const btn = event.currentTarget;
const originalIcon = btn.innerHTML;
btn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
setTimeout(() => btn.innerHTML = originalIcon, 2000);
}
function renderClients() {
const list = document.getElementById('clientList');
const empty = document.getElementById('emptyState');
if (clients.length === 0) {
list.innerHTML = '';
empty.classList.remove('hidden');
return;
}
empty.classList.add('hidden');
list.innerHTML = clients.map(c => `
<div class="bg-white border border-slate-200 rounded-2xl p-5 shadow-sm hover:shadow-md transition-all group">
<div class="flex justify-between items-start mb-4">
<div class="flex items-center gap-3">
<div class="bg-blue-50 text-blue-600 p-2 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
</div>
<div>
<input type="text" value="${c.name}" onchange="updateClientName(${c.id}, this.value)" class="font-bold text-slate-800 border-none bg-transparent outline-none focus:ring-0 w-full p-0">
<p class="text-[10px] font-medium text-slate-400 uppercase tracking-tighter">${c.ip}</p>
</div>
</div>
<button onclick="removeClient(${c.id})" class="text-slate-300 hover:text-red-500 transition-colors opacity-0 group-hover:opacity-100 p-1">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>
</button>
</div>
<div class="flex gap-2 mt-6">
<button onclick="downloadClientConf(${c.id})" class="flex-1 bg-slate-50 text-slate-700 text-xs font-bold py-2.5 rounded-xl hover:bg-blue-50 hover:text-blue-600 transition-colors border border-slate-100 flex items-center justify-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
DOWNLOAD CONFIG
</button>
</div>
</div>
`).join('');
}
function updateClientName(id, name) {
const client = clients.find(c => c.id === id);
if (client) client.name = name;
}
function downloadFile(filename, text) {
const blob = new Blob([text], { type: 'text/plain' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}
function downloadServerConf() {
let conf = `[Interface]\nPrivateKey = ${server.privateKey}\nAddress = ${server.ip}\nListenPort = ${server.port}\n`;
conf += `PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\n`;
conf += `PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE\n\n`;
clients.forEach(c => {
conf += `[Peer]\n# Name: ${c.name}\nPublicKey = ${c.publicKey}\nAllowedIPs = ${c.ip}\n\n`;
});
downloadFile('wg0.conf', conf);
}
function downloadClientConf(id) {
const c = clients.find(cl => cl.id === id);
if (!c) return;
let conf = `[Interface]\nPrivateKey = ${c.privateKey}\nAddress = ${c.ip}\nDNS = ${server.dns}\n\n`;
conf += `[Peer]\nPublicKey = ${server.publicKey}\nEndpoint = ${server.hostname}:${server.port}\nAllowedIPs = 0.0.0.0/0, ::/0\nPersistentKeepalive = ${c.keepalive}\n`;
downloadFile(`${c.name.replace(/\s+/g, '_')}.conf`, conf);
}
window.onload = init;
</script>
</body>
</html>