added registration
This commit is contained in:
parent
9fa1a7d914
commit
22711c30f7
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,4 +1,9 @@
|
|||||||
|
|
||||||
|
keystores/
|
||||||
|
data/
|
||||||
|
|
||||||
.gradle
|
.gradle
|
||||||
|
|
||||||
build/
|
build/
|
||||||
!gradle/wrapper/gradle-wrapper.jar
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
!**/src/main/**/build/
|
!**/src/main/**/build/
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -4,7 +4,7 @@
|
|||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
<file type="web" url="file://$PROJECT_DIR$" />
|
<file type="web" url="file://$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@ -17,7 +17,8 @@ dependencies {
|
|||||||
implementation("org.bouncycastle:bcprov-jdk18on:1.83")
|
implementation("org.bouncycastle:bcprov-jdk18on:1.83")
|
||||||
implementation("org.bouncycastle:bcpkix-jdk18on:1.83")
|
implementation("org.bouncycastle:bcpkix-jdk18on:1.83")
|
||||||
implementation("org.springframework.security:spring-security-crypto:7.1.0-M2")
|
implementation("org.springframework.security:spring-security-crypto:7.1.0-M2")
|
||||||
}
|
|
||||||
|
implementation("commons-logging:commons-logging:1.2")}
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
|
|||||||
9
plan
Normal file
9
plan
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
gui
|
||||||
|
registration screen user type choice, and then needed fields, after registration user gets to download/save his certificate
|
||||||
|
login screen drag/select file location and then unlock the p12 cert, then login screen.
|
||||||
|
|
||||||
|
organizer screen - panel with all current polls, section bellow it for finished polls sorted by latest, above all that <create new poll button>, user can select the previus polls to see vote graphs
|
||||||
|
|
||||||
|
voter screen - only can see ongoing polls and after selection once he gets a radio button select, then after voting he gets notification? on success??
|
||||||
|
|
||||||
|
|
||||||
@ -7,6 +7,7 @@ import org.bouncycastle.asn1.x500.X500Name;
|
|||||||
import org.bouncycastle.asn1.x509.*;
|
import org.bouncycastle.asn1.x509.*;
|
||||||
import org.bouncycastle.cert.X509CertificateHolder;
|
import org.bouncycastle.cert.X509CertificateHolder;
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
||||||
import org.bouncycastle.operator.ContentSigner;
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||||
@ -73,7 +74,7 @@ public class CA {
|
|||||||
|
|
||||||
KeyPair keyPair = KeyService.generateRSAKeyPair();
|
KeyPair keyPair = KeyService.generateRSAKeyPair();
|
||||||
|
|
||||||
X500Name issuer = new X500Name(issuerCert.getSubjectX500Principal().getName());
|
X500Name issuer = new JcaX509CertificateHolder(issuerCert).getSubject();
|
||||||
X500Name subject = new X500Name("CN=" + type + ", O=CA, OU=VotingSystem, L=BL, ST=BA");
|
X500Name subject = new X500Name("CN=" + type + ", O=CA, OU=VotingSystem, L=BL, ST=BA");
|
||||||
|
|
||||||
BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
|
BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
|
||||||
@ -175,7 +176,7 @@ public class CA {
|
|||||||
PublicKey userKey
|
PublicKey userKey
|
||||||
) throws Exception {
|
) throws Exception {
|
||||||
|
|
||||||
X500Name issuer = new X500Name(caCert.getSubjectX500Principal().getName());
|
X500Name issuer = new JcaX509CertificateHolder(caCert).getSubject();
|
||||||
X500Name subject = new X500Name("CN=" + username);
|
X500Name subject = new X500Name("CN=" + username);
|
||||||
|
|
||||||
BigInteger serial = new BigInteger(64, new SecureRandom());
|
BigInteger serial = new BigInteger(64, new SecureRandom());
|
||||||
|
|||||||
65
src/main/java/dev/ksan/CASystem/CAInitializer.java
Normal file
65
src/main/java/dev/ksan/CASystem/CAInitializer.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package dev.ksan.CASystem;
|
||||||
|
|
||||||
|
import dev.ksan.temp.AppConfig;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class CAInitializer {
|
||||||
|
|
||||||
|
private static final Path ROOT_CA_PATH = Path.of("keystores/ca/root-ca.p12");
|
||||||
|
private static final char[] CA_PASSWORD = AppConfig.getCaKeystorePassword();
|
||||||
|
private static final char[] TRUSTSTORE_PASSWORD = AppConfig.getTruststorePassword();
|
||||||
|
|
||||||
|
public static void initializeIfNeeded() {
|
||||||
|
if (Files.exists(ROOT_CA_PATH)) {
|
||||||
|
System.out.println("CA hierarchy already initialized.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
System.out.println("Initializing CA hierarchy for the first time...");
|
||||||
|
|
||||||
|
// 1. Root CA
|
||||||
|
CAResult rootCA = CA.generateRootCA();
|
||||||
|
|
||||||
|
// 2. Sub-CAs signed by Root
|
||||||
|
CAResult organizerCA = CA.generateSubCA(
|
||||||
|
CAType.ORGANIZER,
|
||||||
|
rootCA.getCertificate(),
|
||||||
|
rootCA.getKeyPair().getPrivate()
|
||||||
|
);
|
||||||
|
CAResult voterCA = CA.generateSubCA(
|
||||||
|
CAType.VOTER,
|
||||||
|
rootCA.getCertificate(),
|
||||||
|
rootCA.getKeyPair().getPrivate()
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. Save CA keystores (private keys protected)
|
||||||
|
KeystoreService.saveCAKeyStore("root-ca",
|
||||||
|
rootCA.getKeyPair().getPrivate(), rootCA.getCertificate(), null, CA_PASSWORD);
|
||||||
|
|
||||||
|
KeystoreService.saveCAKeyStore("organizer-ca",
|
||||||
|
organizerCA.getKeyPair().getPrivate(), organizerCA.getCertificate(),
|
||||||
|
rootCA.getCertificate(), CA_PASSWORD);
|
||||||
|
|
||||||
|
KeystoreService.saveCAKeyStore("voter-ca",
|
||||||
|
voterCA.getKeyPair().getPrivate(), voterCA.getCertificate(),
|
||||||
|
rootCA.getCertificate(), CA_PASSWORD);
|
||||||
|
|
||||||
|
// 4. Save truststore (public certs only)
|
||||||
|
TruststoreService.createTruststore(
|
||||||
|
rootCA.getCertificate(),
|
||||||
|
organizerCA.getCertificate(),
|
||||||
|
voterCA.getCertificate(),
|
||||||
|
TRUSTSTORE_PASSWORD
|
||||||
|
);
|
||||||
|
|
||||||
|
System.out.println("CA hierarchy initialized successfully.");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("FATAL: Could not initialize CA hierarchy: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,8 +24,8 @@ public class KeystoreService {
|
|||||||
|
|
||||||
public static void saveUserKeystore(String username,
|
public static void saveUserKeystore(String username,
|
||||||
PrivateKey privateKey,
|
PrivateKey privateKey,
|
||||||
X509Certificate caCert,
|
|
||||||
X509Certificate userCert,
|
X509Certificate userCert,
|
||||||
|
X509Certificate caCert ,
|
||||||
char[] keystorePassword) throws Exception {
|
char[] keystorePassword) throws Exception {
|
||||||
|
|
||||||
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
||||||
@ -61,7 +61,29 @@ public class KeystoreService {
|
|||||||
PrivateKey privateKey,
|
PrivateKey privateKey,
|
||||||
X509Certificate caCert,
|
X509Certificate caCert,
|
||||||
X509Certificate issuerCert,
|
X509Certificate issuerCert,
|
||||||
char[] keystorePassword) throws Exception {}
|
char[] keystorePassword) throws Exception {
|
||||||
|
|
||||||
|
|
||||||
|
KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);
|
||||||
|
ks.load(null, null);
|
||||||
|
|
||||||
|
Certificate[] chain = issuerCert != null ?
|
||||||
|
new Certificate[]{caCert, issuerCert} :
|
||||||
|
new Certificate[]{caCert};
|
||||||
|
|
||||||
|
ks.setKeyEntry( KEY_ALIAS, privateKey, keystorePassword, chain);
|
||||||
|
|
||||||
|
Path path = CA_KEYSTORE_DIR.resolve(caName + ".p12");
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
|
||||||
|
try(FileOutputStream fos = new FileOutputStream(path.toFile())) {
|
||||||
|
ks.store(fos, keystorePassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static KeyStore loadKeyStore(Path path, char[] password) throws Exception {
|
private static KeyStore loadKeyStore(Path path, char[] password) throws Exception {
|
||||||
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
||||||
@ -89,8 +111,6 @@ public class KeystoreService {
|
|||||||
|
|
||||||
return Base64.getEncoder().encodeToString(hash).toCharArray();
|
return Base64.getEncoder().encodeToString(hash).toCharArray();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import dev.ksan.Users.Organizer;
|
|||||||
import dev.ksan.Users.User;
|
import dev.ksan.Users.User;
|
||||||
import dev.ksan.Users.UserRepository;
|
import dev.ksan.Users.UserRepository;
|
||||||
import dev.ksan.Users.Voter;
|
import dev.ksan.Users.Voter;
|
||||||
|
import dev.ksan.temp.AppConfig;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
@ -13,10 +14,8 @@ public class RegistrationService {
|
|||||||
|
|
||||||
// CA certs are loaded from truststore (public, accessible before login)
|
// CA certs are loaded from truststore (public, accessible before login)
|
||||||
// CA private keys are loaded from CA keystores (protected)
|
// CA private keys are loaded from CA keystores (protected)
|
||||||
private static final char[] CA_KEYSTORE_PASSWORD =
|
private static final char[] CA_KEYSTORE_PASSWORD = AppConfig.getCaKeystorePassword();
|
||||||
System.getenv("CA_KEYSTORE_PASSWORD").toCharArray();
|
private static final char[] TRUSTSTORE_PASSWORD = AppConfig.getTruststorePassword();
|
||||||
private static final char[] TRUSTSTORE_PASSWORD =
|
|
||||||
System.getenv("TRUSTSTORE_PASSWORD").toCharArray();
|
|
||||||
|
|
||||||
public static void registerOrganizer(Organizer organizer, String rawPassword)
|
public static void registerOrganizer(Organizer organizer, String rawPassword)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@ -40,27 +39,33 @@ public class RegistrationService {
|
|||||||
organizer.setCertificate(cert);
|
organizer.setCertificate(cert);
|
||||||
|
|
||||||
|
|
||||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
|
try {
|
||||||
String hashedPassword = encoder.encode(rawPassword);
|
|
||||||
|
|
||||||
organizer.setHashedPassword(hashedPassword);
|
|
||||||
|
|
||||||
char[] ksPassword = KeystoreService.deriveKeystorePassword(
|
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
|
||||||
rawPassword,
|
String hashedPassword = encoder.encode(rawPassword);
|
||||||
organizer.getId().toString()
|
|
||||||
);
|
|
||||||
|
|
||||||
KeystoreService.saveUserKeystore(
|
organizer.setHashedPassword(hashedPassword);
|
||||||
organizer.getId().toString(),
|
|
||||||
keyPair.getPrivate(),
|
char[] ksPassword = KeystoreService.deriveKeystorePassword(
|
||||||
cert,
|
rawPassword,
|
||||||
organizerCACert,
|
organizer.getId().toString()
|
||||||
ksPassword
|
);
|
||||||
);
|
|
||||||
if (UserRepository.voterExists(organizer.getId().toString())) {
|
KeystoreService.saveUserKeystore(
|
||||||
throw new IllegalStateException("Id already taken: " + organizer.getId());
|
organizer.getId().toString(),
|
||||||
|
keyPair.getPrivate(),
|
||||||
|
cert,
|
||||||
|
organizerCACert,
|
||||||
|
ksPassword
|
||||||
|
);
|
||||||
|
if (UserRepository.voterExists(organizer.getId().toString())) {
|
||||||
|
throw new IllegalStateException("Id already taken: " + organizer.getId());
|
||||||
|
}
|
||||||
|
UserRepository.save(organizer);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
UserRepository.save(organizer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerVoter(Voter voter, String rawPassword)
|
public static void registerVoter(Voter voter, String rawPassword)
|
||||||
|
|||||||
@ -28,6 +28,7 @@ public class TruststoreService {
|
|||||||
ts.setCertificateEntry("voter-ca", voterCACert);
|
ts.setCertificateEntry("voter-ca", voterCACert);
|
||||||
|
|
||||||
Files.createDirectories(TRUSTSTORE_PATH.getParent());
|
Files.createDirectories(TRUSTSTORE_PATH.getParent());
|
||||||
|
|
||||||
try (OutputStream os = Files.newOutputStream(TRUSTSTORE_PATH)) {
|
try (OutputStream os = Files.newOutputStream(TRUSTSTORE_PATH)) {
|
||||||
ts.store(os, truststorePassword);
|
ts.store(os, truststorePassword);
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/main/java/dev/ksan/ConsoleApp.java
Normal file
26
src/main/java/dev/ksan/ConsoleApp.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package dev.ksan;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
// TODO temp class for testing functionality
|
||||||
|
|
||||||
|
public class ConsoleApp {
|
||||||
|
|
||||||
|
private final Scanner scanner = new Scanner(System.in);
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
while (true) {
|
||||||
|
System.out.println("\n=== E-Voting System ===");
|
||||||
|
System.out.println("1. Register");
|
||||||
|
System.out.println("0. Exit");
|
||||||
|
System.out.print("Choose: ");
|
||||||
|
|
||||||
|
switch (scanner.nextLine().trim()) {
|
||||||
|
case "1" -> new RegistrationUI(scanner).show();
|
||||||
|
case "2" -> System.out.println("Login not yet implemented");
|
||||||
|
case "0" -> { System.out.println("Goodbye."); return; }
|
||||||
|
default -> System.out.println("Invalid option.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,6 @@
|
|||||||
package dev.ksan;
|
package dev.ksan;
|
||||||
|
|
||||||
import dev.ksan.CASystem.CA;
|
import dev.ksan.CASystem.*;
|
||||||
import dev.ksan.CASystem.CAResult;
|
|
||||||
import dev.ksan.CASystem.CAType;
|
|
||||||
import dev.ksan.CASystem.KeyService;
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
@ -14,40 +11,48 @@ import static dev.ksan.CASystem.CA.publicKeyToPem;
|
|||||||
|
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
static{
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
}
|
||||||
public static void main(String args[]) throws Exception {
|
public static void main(String args[]) throws Exception {
|
||||||
|
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
// System.out.println("added bouncycastle provider");
|
||||||
System.out.println("added bouncycastle provider");
|
// KeyPair key =KeyService.generateRSAKeyPair();
|
||||||
KeyPair key =KeyService.generateRSAKeyPair();
|
// System.out.println(key.getPrivate());
|
||||||
System.out.println(key.getPrivate());
|
// System.out.println(key.getPublic());
|
||||||
System.out.println(key.getPublic());
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// int maxKeySize = javax.crypto.Cipher.getMaxAllowedKeyLength("AES");
|
||||||
|
// System.out.println("Max Key Size for AES : " + maxKeySize);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// System.out.println("test cert");
|
||||||
|
//
|
||||||
|
// CAResult cert = CA.generateRootCA();
|
||||||
|
// System.out.println(cert.getCertificate().toString());
|
||||||
|
//
|
||||||
|
// System.out.println("test cert");
|
||||||
|
// System.out.println("test cert");
|
||||||
|
// System.out.println("test cert");
|
||||||
|
// System.out.println("test cert");
|
||||||
|
// CAResult prvi = CA.generateSubCA(CAType.VOTER ,cert.getCertificate(),cert.getKeyPair().getPrivate());
|
||||||
|
// System.out.println(prvi.getCertificate().toString());
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// String publicKeyPem = publicKeyToPem(cert.getCertificate().getPublicKey());
|
||||||
|
// System.out.println("Public Key PEM:\n" + publicKeyPem);
|
||||||
|
//
|
||||||
|
// System.out.println(CA.validateCertificate(prvi.getCertificate(),cert.getCertificate()));
|
||||||
|
// System.out.println(CA.validateCertificate(cert.getCertificate(),cert.getCertificate()));
|
||||||
|
// System.out.println(CA.validateCertificate(cert.getCertificate(),prvi.getCertificate()));
|
||||||
|
|
||||||
|
|
||||||
|
CAInitializer.initializeIfNeeded();
|
||||||
|
|
||||||
int maxKeySize = javax.crypto.Cipher.getMaxAllowedKeyLength("AES");
|
ConsoleApp app = new ConsoleApp();
|
||||||
System.out.println("Max Key Size for AES : " + maxKeySize);
|
app.start();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
System.out.println("test cert");
|
|
||||||
|
|
||||||
CAResult cert = CA.generateRootCA();
|
|
||||||
System.out.println(cert.getCertificate().toString());
|
|
||||||
|
|
||||||
System.out.println("test cert");
|
|
||||||
System.out.println("test cert");
|
|
||||||
System.out.println("test cert");
|
|
||||||
System.out.println("test cert");
|
|
||||||
CAResult prvi = CA.generateSubCA(CAType.VOTER ,cert.getCertificate(),cert.getKeyPair().getPrivate());
|
|
||||||
System.out.println(prvi.getCertificate().toString());
|
|
||||||
|
|
||||||
|
|
||||||
String publicKeyPem = publicKeyToPem(cert.getCertificate().getPublicKey());
|
|
||||||
System.out.println("Public Key PEM:\n" + publicKeyPem);
|
|
||||||
|
|
||||||
System.out.println(CA.validateCertificate(prvi.getCertificate(),cert.getCertificate()));
|
|
||||||
System.out.println(CA.validateCertificate(cert.getCertificate(),cert.getCertificate()));
|
|
||||||
System.out.println(CA.validateCertificate(cert.getCertificate(),prvi.getCertificate()));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
114
src/main/java/dev/ksan/RegistrationUI.java
Normal file
114
src/main/java/dev/ksan/RegistrationUI.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package dev.ksan;
|
||||||
|
|
||||||
|
import dev.ksan.CASystem.RegistrationService;
|
||||||
|
import dev.ksan.Users.Organizer;
|
||||||
|
import dev.ksan.Users.UserRepository;
|
||||||
|
import dev.ksan.Users.Voter;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class RegistrationUI {
|
||||||
|
|
||||||
|
private final Scanner scanner;
|
||||||
|
|
||||||
|
public RegistrationUI(Scanner scanner) {
|
||||||
|
this.scanner = scanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
System.out.println("\n-- Register --");
|
||||||
|
System.out.println("1. Register as Organizer");
|
||||||
|
System.out.println("2. Register as Voter");
|
||||||
|
System.out.print("Choose: ");
|
||||||
|
|
||||||
|
switch (scanner.nextLine().trim()) {
|
||||||
|
case "1" -> registerOrganizer();
|
||||||
|
case "2" -> registerVoter();
|
||||||
|
default -> System.out.println("Invalid option.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerOrganizer() {
|
||||||
|
try {
|
||||||
|
System.out.print("Organization name: ");
|
||||||
|
String orgName = scanner.nextLine().trim();
|
||||||
|
|
||||||
|
System.out.print("Identification number: ");
|
||||||
|
String idNumber = scanner.nextLine().trim();
|
||||||
|
|
||||||
|
if (UserRepository.organizerExists(idNumber)) {
|
||||||
|
System.out.println("An organizer with that ID already exists.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String password = readAndConfirmPassword();
|
||||||
|
if (password == null) return; // passwords didn't match
|
||||||
|
|
||||||
|
Organizer organizer = new Organizer(orgName, (idNumber));
|
||||||
|
|
||||||
|
System.out.println("Registering, please wait...");
|
||||||
|
RegistrationService.registerOrganizer(organizer, password);
|
||||||
|
|
||||||
|
System.out.println("Organizer registered successfully.");
|
||||||
|
System.out.println("Your keystore is saved at: keystores/users/" + idNumber + ".p12");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Registration failed: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerVoter() {
|
||||||
|
try {
|
||||||
|
System.out.print("First name: ");
|
||||||
|
String firstName = scanner.nextLine().trim();
|
||||||
|
|
||||||
|
System.out.print("Last name: ");
|
||||||
|
String lastName = scanner.nextLine().trim();
|
||||||
|
|
||||||
|
System.out.print("Username: ");
|
||||||
|
String username = scanner.nextLine().trim();
|
||||||
|
|
||||||
|
if (UserRepository.voterExists(username)) {
|
||||||
|
System.out.println("That username is already taken.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String password = readAndConfirmPassword();
|
||||||
|
if (password == null) return;
|
||||||
|
|
||||||
|
Voter voter = new Voter(firstName, lastName, username);
|
||||||
|
|
||||||
|
System.out.println("Registering, please wait...");
|
||||||
|
RegistrationService.registerVoter(voter, password);
|
||||||
|
|
||||||
|
System.out.println("Voter registered successfully.");
|
||||||
|
System.out.println("Your keystore is saved at: keystores/users/" + username + ".p12");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Registration failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask for password twice to catch typos
|
||||||
|
private String readAndConfirmPassword() {
|
||||||
|
System.out.print("Password: ");
|
||||||
|
String password = scanner.nextLine();
|
||||||
|
|
||||||
|
System.out.print("Confirm password: ");
|
||||||
|
String confirm = scanner.nextLine();
|
||||||
|
|
||||||
|
if (!password.equals(confirm)) {
|
||||||
|
System.out.println("Passwords do not match.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.length() < 3) {
|
||||||
|
System.out.println("Password must be at least 8 characters.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,14 +13,12 @@ public class Organizer extends User {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private String name;
|
private String name;
|
||||||
private UUID id;
|
private String id;
|
||||||
private String password;
|
|
||||||
|
|
||||||
public Organizer(String name, UUID id, String password) {
|
public Organizer(String name, String id) {
|
||||||
super();
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.password = password;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,13 +26,9 @@ public class Organizer extends User {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getOrganizationName() {
|
public String getOrganizationName() {
|
||||||
return getName();
|
return getName();
|
||||||
|
|||||||
@ -4,11 +4,10 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
import java.nio.channels.FileLock;
|
import java.nio.channels.FileLock;
|
||||||
import java.nio.file.DirectoryStream;
|
import java.nio.file.*;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -125,16 +124,15 @@ public class UserRepository {
|
|||||||
private static void writeToFile(User user, Path targetPath) throws Exception {
|
private static void writeToFile(User user, Path targetPath) throws Exception {
|
||||||
Path tmpPath = targetPath.resolveSibling(targetPath.getFileName() + ".tmp");
|
Path tmpPath = targetPath.resolveSibling(targetPath.getFileName() + ".tmp");
|
||||||
|
|
||||||
try (FileOutputStream fos = new FileOutputStream(tmpPath.toFile());
|
// Open a temporary file and write the object
|
||||||
FileLock fileLock = fos.getChannel().lock();
|
try (ObjectOutputStream oos = new ObjectOutputStream(
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
|
Files.newOutputStream(tmpPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
|
||||||
|
|
||||||
oos.writeObject(user);
|
oos.writeObject(user);
|
||||||
oos.flush();
|
oos.flush();
|
||||||
// fileLock released automatically on close
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Files.move(tmpPath, targetPath, StandardCopyOption.ATOMIC_MOVE,
|
Files.move(tmpPath, targetPath,
|
||||||
|
StandardCopyOption.ATOMIC_MOVE,
|
||||||
StandardCopyOption.REPLACE_EXISTING);
|
StandardCopyOption.REPLACE_EXISTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,14 +6,14 @@ public class Voter extends User {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private String name;
|
private String name;
|
||||||
|
private String lastName;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
|
||||||
|
|
||||||
public Voter(String name, String username, String password){
|
public Voter(String name, String username, String lastName){
|
||||||
super();
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.lastName = lastName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName(){
|
public String getName(){
|
||||||
@ -24,6 +24,6 @@ public class Voter extends User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getPassword(){
|
public String getPassword(){
|
||||||
return password;
|
return lastName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/main/java/dev/ksan/temp/AppConfig.java
Normal file
17
src/main/java/dev/ksan/temp/AppConfig.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package dev.ksan.temp;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class AppConfig {
|
||||||
|
|
||||||
|
private static final char[] CA_KEYSTORE_PASSWORD = "ca-keystore-password-123".toCharArray();
|
||||||
|
private static final char[] TRUSTSTORE_PASSWORD = "truststore-password-123".toCharArray();
|
||||||
|
|
||||||
|
public static char[] getCaKeystorePassword() {
|
||||||
|
return Arrays.copyOf(CA_KEYSTORE_PASSWORD, CA_KEYSTORE_PASSWORD.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static char[] getTruststorePassword() {
|
||||||
|
return Arrays.copyOf(TRUSTSTORE_PASSWORD, TRUSTSTORE_PASSWORD.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user