130 lines
5.0 KiB
JavaScript
130 lines
5.0 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Link, useNavigate } from 'react-router-dom';
|
|
|
|
const Register = () => {
|
|
const [username, setUsername] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [error, setError] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
const navigate = useNavigate();
|
|
|
|
const handleRegister = async (e) => {
|
|
e.preventDefault();
|
|
setError('');
|
|
setLoading(true);
|
|
|
|
try {
|
|
console.log('Starting registration for:', username);
|
|
|
|
// 1. Generate Salt and Master Key (MK)
|
|
const salt = await window.cryptoAPI.randomBytes(16);
|
|
const mk = await window.cryptoAPI.randomBytes(16); // 128-bit MK
|
|
|
|
console.log('Generated Salt and MK');
|
|
|
|
// 2. Derive Keys (DEK, DAK)
|
|
const { dek, dak } = await window.cryptoAPI.deriveAuthKeys(password, salt);
|
|
console.log('Derived keys');
|
|
|
|
// 3. Encrypt MK with DEK
|
|
const encryptedMKObj = await window.cryptoAPI.encryptData(mk, dek);
|
|
const encryptedMK = JSON.stringify(encryptedMKObj); // Store as JSON string {content, tag, iv}
|
|
|
|
// 4. Hash DAK for Auth Proof
|
|
const hak = await window.cryptoAPI.sha256(dak);
|
|
|
|
// 5. Generate Key Pairs
|
|
const keys = await window.cryptoAPI.generateKeys();
|
|
|
|
// 6. Encrypt Private Keys with MK
|
|
// We need to encrypt the private keys so the server can store them safely
|
|
// MK is used to encrypt these.
|
|
const encryptedRsaPriv = await window.cryptoAPI.encryptData(keys.rsaPriv, mk);
|
|
const encryptedEdPriv = await window.cryptoAPI.encryptData(keys.edPriv, mk);
|
|
|
|
const encryptedPrivateKeys = JSON.stringify({
|
|
rsa: encryptedRsaPriv,
|
|
ed: encryptedEdPriv
|
|
});
|
|
|
|
// 7. Send to Backend
|
|
const payload = {
|
|
username,
|
|
salt,
|
|
encryptedMK,
|
|
hak,
|
|
publicKey: keys.rsaPub,
|
|
signingKey: keys.edPub,
|
|
encryptedPrivateKeys // Note: Schema might need this column or we pack it into another
|
|
};
|
|
|
|
// NOTE: The schema in overview.md had 'Encrypted Private Keys' in the text but not explicitly in the SQL CREATE TABLE snippet provided in the prompt's overview.md (it was in the text description).
|
|
// The SQL snippet had: encrypted_master_key, hashed_auth_key, public_identity_key, public_signing_key.
|
|
// It did NOT have a column for encrypted_private_keys in the SQL block in overview.md.
|
|
// I should check schema.sql I created.
|
|
|
|
const response = await fetch('http://localhost:3000/api/auth/register', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload)
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new Error(data.error || 'Registration failed');
|
|
}
|
|
|
|
console.log('Registration successful:', data);
|
|
navigate('/');
|
|
} catch (err) {
|
|
console.error('Registration error:', err);
|
|
setError(err.message);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="auth-container">
|
|
<div className="auth-box">
|
|
<div className="auth-header">
|
|
<h2>Create an Account</h2>
|
|
<p>Join the secure chat!</p>
|
|
</div>
|
|
{error && <div style={{ color: 'red', marginBottom: 10, textAlign: 'center' }}>{error}</div>}
|
|
<form onSubmit={handleRegister}>
|
|
<div className="form-group">
|
|
<label>Username</label>
|
|
<input
|
|
type="text"
|
|
value={username}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
required
|
|
disabled={loading}
|
|
/>
|
|
</div>
|
|
<div className="form-group">
|
|
<label>Password</label>
|
|
<input
|
|
type="password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
required
|
|
disabled={loading}
|
|
/>
|
|
</div>
|
|
<button type="submit" className="auth-button" disabled={loading}>
|
|
{loading ? 'Generating Keys...' : 'Continue'}
|
|
</button>
|
|
</form>
|
|
<div className="auth-footer">
|
|
Already have an account? <Link to="/">Log In</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Register;
|