package ch.ge.ve.offlineadmin.services;
/*-
* #%L
* Admin offline
* %%
* Copyright (C) 2015 - 2016 République et Canton de Genève
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import ch.ge.ve.commons.crypto.ballot.BallotCipherService;
import ch.ge.ve.commons.crypto.exceptions.CryptoConfigurationRuntimeException;
import ch.ge.ve.commons.fileutils.OutputFilesPattern;
import ch.ge.ve.commons.properties.PropertyConfigurationException;
import ch.ge.ve.commons.properties.PropertyConfigurationService;
import ch.ge.ve.offlineadmin.exception.MissingKeyFilesException;
import com.google.common.base.Preconditions;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
import static ch.ge.ve.offlineadmin.util.SecurityConstants.*;
/**
* This factory creates instances of {@link ch.ge.ve.commons.crypto.ballot.BallotCipherService} either for encryption or
* for decryption, by being given a directory where the encryption/decryption keys are located.
* It verifies that the expected files are present in the directory and instantiates the
* {@link ch.ge.ve.commons.crypto.ballot.BallotCipherService} accordingly.
*/
public class BallotCipherServiceFactory {
private final OutputFilesPattern outputFilesPattern = new OutputFilesPattern();
private final PropertyConfigurationService propertyConfigurationService;
private String integrityKeyFilenamePatternProperty;
private String privateKeyFilenamePatternProperty;
private String publicKeyFilenamePatternProperty;
public BallotCipherServiceFactory(PropertyConfigurationService propertyConfigurationService) {
this.propertyConfigurationService = propertyConfigurationService;
init(propertyConfigurationService);
}
private void init(PropertyConfigurationService propertyConfigurationService) {
try {
integrityKeyFilenamePatternProperty = propertyConfigurationService.getConfigValue(INTEGRITY_KEY_FILENAME_PATTERN);
publicKeyFilenamePatternProperty = propertyConfigurationService.getConfigValue(CERT_PUBLIC_KEY_FILENAME_PATTERN);
privateKeyFilenamePatternProperty = propertyConfigurationService.getConfigValue(CERT_PRIVATE_KEY_FILENAME_PATTERN);
} catch (PropertyConfigurationException e) {
throw new CryptoConfigurationRuntimeException("key files names configuration missing", e);
}
}
/**
* Creates an instance of a {@link ch.ge.ve.commons.crypto.ballot.BallotCipherService} for encryption
*
* @param keyDirectory the directory containing the keys
* @return an initialized {@link ch.ge.ve.commons.crypto.ballot.BallotCipherService} ready for encryption
* @throws MissingKeyFilesException if the directory does not contain the expected files
*/
public BallotCipherService encryptionBallotCipherService(File keyDirectory) throws MissingKeyFilesException {
Preconditions.checkNotNull(keyDirectory);
Preconditions.checkArgument(keyDirectory.isDirectory());
EncryptionBallotCiphersProvider ciphersProvider = new EncryptionBallotCiphersProvider();
List<Pattern> expectedFilesNamePatterns = new ArrayList<>();
Pattern integrityKeyFileNamePattern = Pattern.compile(integrityKeyFilenamePatternProperty);
expectedFilesNamePatterns.add(integrityKeyFileNamePattern);
Pattern publicKeyFilenamePattern = Pattern.compile(publicKeyFilenamePatternProperty);
expectedFilesNamePatterns.add(publicKeyFilenamePattern);
directoryContainsRequiredKeys(keyDirectory, expectedFilesNamePatterns);
BallotCipherService ballotCipherService = new BallotCipherService(ciphersProvider, propertyConfigurationService);
final Optional<Path> integrityKeyPath = outputFilesPattern.findFirstFileByPattern(integrityKeyFileNamePattern, keyDirectory.toPath());
ballotCipherService.setIntegrityKeyFileName(
integrityKeyPath
.orElseThrow(() -> new MissingKeyFilesException("integrity key file not found in directory: " + keyDirectory.getAbsolutePath()))
.toString()
);
final Optional<Path> pubKeyPath = outputFilesPattern.findFirstFileByPattern(publicKeyFilenamePattern, keyDirectory.toPath());
ballotCipherService.setPublicKeyFileName(
pubKeyPath
.orElseThrow(() -> new MissingKeyFilesException("public key file not found in directory: " + keyDirectory.getAbsolutePath()))
.toString()
);
return ballotCipherService;
}
/**
* Creates an instance of a {@link ch.ge.ve.commons.crypto.ballot.BallotCipherService} for decryption
*
* @param keyDirectory the directory containing the keys
* @return an initialized {@link ch.ge.ve.commons.crypto.ballot.BallotCipherService} ready for decryption
* @throws MissingKeyFilesException if the directory does not contain the expected files
*/
public BallotCipherService decryptionBallotCipherService(File keyDirectory) throws MissingKeyFilesException {
Preconditions.checkNotNull(keyDirectory);
Preconditions.checkArgument(keyDirectory.isDirectory());
DecryptionBallotCiphersProvider ciphersProvider = new DecryptionBallotCiphersProvider(keyDirectory);
List<Pattern> expectedFilesNamesPatterns = new ArrayList<>();
Pattern integrityKeyFileNamePattern = Pattern.compile(integrityKeyFilenamePatternProperty);
expectedFilesNamesPatterns.add(integrityKeyFileNamePattern);
Pattern privateKeyFilenamePattern = Pattern.compile(privateKeyFilenamePatternProperty);
expectedFilesNamesPatterns.add(privateKeyFilenamePattern);
directoryContainsRequiredKeys(keyDirectory, expectedFilesNamesPatterns);
BallotCipherService ballotCipherService = new BallotCipherService(ciphersProvider, propertyConfigurationService);
final Optional<Path> integrityKeyPath = outputFilesPattern.findFirstFileByPattern(integrityKeyFileNamePattern, keyDirectory.toPath());
ballotCipherService.setIntegrityKeyFileName(
integrityKeyPath
.orElseThrow(() -> new MissingKeyFilesException("integrity key file not found in directory: " + keyDirectory.getAbsolutePath()))
.toString()
);
final Optional<Path> privKeyPath = outputFilesPattern.findFirstFileByPattern(privateKeyFilenamePattern, keyDirectory.toPath());
ballotCipherService.setPrivateKeyFileName(
privKeyPath
.orElseThrow(() -> new MissingKeyFilesException("private key file not found in directory: " + keyDirectory.getAbsolutePath()))
.toString()
);
return ballotCipherService;
}
private void directoryContainsRequiredKeys(File keyDirectory, List<Pattern> expectedFilesNames) throws MissingKeyFilesException {
List<String> filenames = Arrays.asList(keyDirectory.list());
if (!expectedFilesNames.stream().allMatch(pattern -> filenames.stream().anyMatch(pattern.asPredicate()))) {
throw new MissingKeyFilesException("key files not found in directory: " + keyDirectory.getAbsolutePath());
}
}
}