2024-12-30 07:07:53 +00:00
|
|
|
// Base64 encoding/decoding utilities with error handling
|
2024-12-30 06:03:07 +00:00
|
|
|
const b64 = {
|
2024-12-30 07:07:53 +00:00
|
|
|
encode: (array) => {
|
|
|
|
try {
|
|
|
|
return btoa(String.fromCharCode.apply(null, array));
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Base64 encoding failed:', error);
|
|
|
|
throw new Error('Failed to encode key data');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
decode: (str) => {
|
|
|
|
try {
|
|
|
|
return Uint8Array.from(atob(str), c => c.charCodeAt(0));
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Base64 decoding failed:', error);
|
|
|
|
throw new Error('Failed to decode key data');
|
|
|
|
}
|
2024-12-30 06:03:07 +00:00
|
|
|
}
|
2024-12-30 07:07:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Key storage management
|
|
|
|
const keyStorage = {
|
|
|
|
store: (userId, keyData) => {
|
|
|
|
try {
|
|
|
|
const data = {
|
|
|
|
privateKey: keyData.privateKey,
|
|
|
|
publicKey: keyData.publicKey,
|
|
|
|
createdAt: new Date().toISOString()
|
|
|
|
};
|
|
|
|
localStorage.setItem(`vpn_keys_${userId}`, JSON.stringify(data));
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to store keys:', error);
|
|
|
|
throw new Error('Failed to save key data');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
retrieve: (userId) => {
|
|
|
|
try {
|
|
|
|
const data = localStorage.getItem(`vpn_keys_${userId}`);
|
|
|
|
return data ? JSON.parse(data) : null;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to retrieve keys:', error);
|
|
|
|
throw new Error('Failed to retrieve key data');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
remove: (userId) => {
|
|
|
|
try {
|
|
|
|
localStorage.removeItem(`vpn_keys_${userId}`);
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to remove keys:', error);
|
|
|
|
}
|
2024-12-30 06:03:07 +00:00
|
|
|
}
|
2024-12-30 07:07:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Main key generation function
|
|
|
|
async function generateKeyPair() {
|
|
|
|
try {
|
|
|
|
const keyPair = await window.crypto.subtle.generateKey(
|
|
|
|
{
|
|
|
|
name: 'X25519',
|
|
|
|
namedCurve: 'X25519',
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
['deriveKey', 'deriveBits']
|
|
|
|
);
|
|
|
|
|
|
|
|
const privateKey = await window.crypto.subtle.exportKey('raw', keyPair.privateKey);
|
|
|
|
const publicKey = await window.crypto.subtle.exportKey('raw', keyPair.publicKey);
|
|
|
|
|
|
|
|
return {
|
|
|
|
privateKey: b64.encode(new Uint8Array(privateKey)),
|
|
|
|
publicKey: b64.encode(new Uint8Array(publicKey))
|
|
|
|
};
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Key generation failed:', error);
|
|
|
|
throw new Error('Failed to generate WireGuard keys');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Key validation function
|
|
|
|
function validateKey(key) {
|
|
|
|
try {
|
|
|
|
const decoded = b64.decode(key);
|
|
|
|
return decoded.length === 32;
|
|
|
|
} catch {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WireGuard config generation
|
|
|
|
function generateConfig(keys, serverPublicKey, serverEndpoint, clientIp) {
|
|
|
|
if (!keys || !serverPublicKey || !serverEndpoint || !clientIp) {
|
|
|
|
throw new Error('Missing required configuration parameters');
|
|
|
|
}
|
|
|
|
|
|
|
|
return `[Interface]
|
|
|
|
PrivateKey = ${keys.privateKey}
|
|
|
|
Address = ${clientIp}/24
|
|
|
|
DNS = 1.1.1.1
|
|
|
|
|
|
|
|
[Peer]
|
|
|
|
PublicKey = ${serverPublicKey}
|
|
|
|
Endpoint = ${serverEndpoint}:51820
|
|
|
|
AllowedIPs = 0.0.0.0/0
|
|
|
|
PersistentKeepalive = 25`;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Main interface for key management
|
|
|
|
export const WireGuard = {
|
|
|
|
generateKeys: async () => {
|
2024-12-30 06:03:07 +00:00
|
|
|
return await generateKeyPair();
|
2024-12-30 07:07:53 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
saveKeys: (userId, keyPair) => {
|
|
|
|
if (!validateKey(keyPair.publicKey) || !validateKey(keyPair.privateKey)) {
|
|
|
|
throw new Error('Invalid key data');
|
|
|
|
}
|
|
|
|
keyStorage.store(userId, keyPair);
|
|
|
|
},
|
|
|
|
|
|
|
|
getKeys: (userId) => {
|
|
|
|
return keyStorage.retrieve(userId);
|
|
|
|
},
|
|
|
|
|
|
|
|
removeKeys: (userId) => {
|
|
|
|
keyStorage.remove(userId);
|
|
|
|
},
|
|
|
|
|
|
|
|
generateConfig,
|
|
|
|
validateKey
|
|
|
|
};
|
|
|
|
|
|
|
|
export default WireGuard;
|