Tony CHEMIT pushed to branch develop at ultreiaio / ird-observe
Commits:
-
2b2f14d4
by Tony Chemit at 2023-10-05T20:31:51+02:00
-
e2385264
by Tony Chemit at 2023-10-06T09:52:51+02:00
11 changed files:
- client/configuration/src/main/config/Client.ini
- client/configuration/src/main/i18n/getters/config.getter
- client/configuration/src/main/i18n/getters/java.getter
- client/configuration/src/main/java/fr/ird/observe/client/configuration/ClientConfig.java
- client/configuration/src/main/java/fr/ird/observe/client/configuration/ClientResources.java
- + client/configuration/src/main/resources/observe.jks
- client/core/src/main/java/fr/ird/observe/client/datasource/h2/backup/BackupsManager.java
- client/core/src/main/java/fr/ird/observe/client/main/body/ClientConfigUI.java
- client/runner/src/main/i18n/translations/client-runner_en_GB.properties
- client/runner/src/main/i18n/translations/client-runner_es_ES.properties
- client/runner/src/main/i18n/translations/client-runner_fr_FR.properties
Changes:
| ... | ... | @@ -331,6 +331,12 @@ type = file |
| 331 | 331 | defaultValue = ${instance.resources.directory}/observe-log4j2.xml
|
| 332 | 332 | transient = true
|
| 333 | 333 | |
| 334 | +[option useJvmKeyStore]
|
|
| 335 | +description = observe.config.useJvmKeyStore.description
|
|
| 336 | +key = instance.useJvmKeyStore
|
|
| 337 | +type = Boolean
|
|
| 338 | +defaultValue = false
|
|
| 339 | + |
|
| 334 | 340 | [option longlineActivityPairingMaxDistance]
|
| 335 | 341 | description = observe.config.longlineActivityPairing.maxDistance
|
| 336 | 342 | key = instance.longlineActivityPairing.maxDistance
|
| ... | ... | @@ -153,6 +153,7 @@ observe.config.ui.tree.node.disabled.color |
| 153 | 153 | observe.config.ui.tree.node.empty.color
|
| 154 | 154 | observe.config.ui.tree.node.unloaded.color
|
| 155 | 155 | observe.config.ui.tree.node.unsaved.color
|
| 156 | +observe.config.useJvmKeyStore.description
|
|
| 156 | 157 | observe.config.validation.lengthWeightEnable
|
| 157 | 158 | observe.config.validation.speedEnable
|
| 158 | 159 | observe.config.validation.speedMaxValue
|
| ... | ... | @@ -5,7 +5,9 @@ observe.runner.copy.default.map.file |
| 5 | 5 | observe.runner.copy.default.report.file
|
| 6 | 6 | observe.runner.copy.default.swing.preferences.file
|
| 7 | 7 | observe.runner.copy.default.ui.file
|
| 8 | +observe.runner.copy.embedded.keystore.file
|
|
| 8 | 9 | observe.runner.loading.ui.configuration
|
| 10 | +observe.runner.use.embedded.keystore.file
|
|
| 9 | 11 | observe.ui.message.save.configuration
|
| 10 | 12 | observe.warning.nimbus.landf
|
| 11 | 13 | observe.warning.no.ui |
| ... | ... | @@ -430,6 +430,26 @@ public class ClientConfig extends GeneratedClientConfig implements TripMapConfig |
| 430 | 430 | |
| 431 | 431 | // 11 - export directory
|
| 432 | 432 | createDirectory(ClientConfigOption.EXPORT_DIRECTORY);
|
| 433 | + |
|
| 434 | + // 12 - Add custom keystore (See https://gitlab.com/ultreiaio/ird-observe/-/issues/2791)
|
|
| 435 | + |
|
| 436 | + Path keystore = resourcesDirectory.toPath().resolve("observe.jks");
|
|
| 437 | + if (Files.notExists(keystore)) {
|
|
| 438 | + String message = t("observe.runner.copy.embedded.keystore.file", keystore);
|
|
| 439 | + log.info(message);
|
|
| 440 | + ClientResources.KEYSTORE.copyResource(keystore.toFile());
|
|
| 441 | + }
|
|
| 442 | + |
|
| 443 | + if (!isUseJvmKeyStore()) {
|
|
| 444 | + String message = t("observe.runner.use.embedded.keystore.file", keystore);
|
|
| 445 | + log.info(message);
|
|
| 446 | + System.setProperty("javax.net.ssl.trustStore", keystore.toString());
|
|
| 447 | + System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
|
|
| 448 | + } else {
|
|
| 449 | + System.clearProperty("javax.net.ssl.trustStore");
|
|
| 450 | + System.clearProperty("javax.net.ssl.trustStorePassword");
|
|
| 451 | + }
|
|
| 452 | + |
|
| 433 | 453 | }
|
| 434 | 454 | |
| 435 | 455 | public void detectLocalDataBase() {
|
| ... | ... | @@ -42,4 +42,5 @@ public final class ClientResources { |
| 42 | 42 | public static final ConfigResource LOG_CONFIGURATION_FILE = new ConfigResource("/observe-log4j2.xml");
|
| 43 | 43 | public static final ConfigResource DCP_PRESETS = new ConfigResource("/dcp-presets.zip");
|
| 44 | 44 | public static final ConfigResource mapLayers = new ConfigResource("/map.zip");
|
| 45 | + public static final ConfigResource KEYSTORE = new ConfigResource("/observe.jks");
|
|
| 45 | 46 | } |
| ... | ... | @@ -23,6 +23,7 @@ package fr.ird.observe.client.datasource.h2.backup; |
| 23 | 23 | */
|
| 24 | 24 | |
| 25 | 25 | import com.google.gson.Gson;
|
| 26 | +import com.google.gson.GsonBuilder;
|
|
| 26 | 27 | import com.google.gson.reflect.TypeToken;
|
| 27 | 28 | import fr.ird.observe.client.configuration.ClientConfig;
|
| 28 | 29 | import fr.ird.observe.client.datasource.api.ObserveDataSourcesManager;
|
| ... | ... | @@ -30,10 +31,10 @@ import fr.ird.observe.client.datasource.api.ObserveSwingDataSource; |
| 30 | 31 | import fr.ird.observe.client.datasource.api.event.ObserveSwingDataSourceEvent;
|
| 31 | 32 | import fr.ird.observe.client.datasource.api.event.ObserveSwingDataSourceListenerAdapter;
|
| 32 | 33 | import fr.ird.observe.client.util.ObserveSwingTechnicalException;
|
| 33 | -import io.ultreia.java4all.lang.Strings;
|
|
| 34 | +import io.ultreia.java4all.util.json.adapters.DateAdapter;
|
|
| 35 | +import io.ultreia.java4all.util.sql.SqlScript;
|
|
| 34 | 36 | import org.apache.logging.log4j.LogManager;
|
| 35 | 37 | import org.apache.logging.log4j.Logger;
|
| 36 | -import io.ultreia.java4all.util.sql.SqlScript;
|
|
| 37 | 38 | |
| 38 | 39 | import java.io.BufferedReader;
|
| 39 | 40 | import java.io.BufferedWriter;
|
| ... | ... | @@ -41,12 +42,8 @@ import java.io.Closeable; |
| 41 | 42 | import java.io.IOException;
|
| 42 | 43 | import java.lang.reflect.Type;
|
| 43 | 44 | import java.nio.charset.StandardCharsets;
|
| 44 | -import java.nio.file.FileVisitResult;
|
|
| 45 | 45 | import java.nio.file.Files;
|
| 46 | 46 | import java.nio.file.Path;
|
| 47 | -import java.nio.file.SimpleFileVisitor;
|
|
| 48 | -import java.nio.file.attribute.BasicFileAttributes;
|
|
| 49 | -import java.util.ArrayList;
|
|
| 50 | 47 | import java.util.Comparator;
|
| 51 | 48 | import java.util.Date;
|
| 52 | 49 | import java.util.Iterator;
|
| ... | ... | @@ -69,11 +66,11 @@ public class BackupsManager implements Closeable { |
| 69 | 66 | |
| 70 | 67 | private static final Pattern AUTOMATIC_BACKUP_FILENAME_PATTERN = Pattern.compile("obs.+-([0-9-]+)\\.sql\\.gz");
|
| 71 | 68 | |
| 72 | - private final Path backupsPath;
|
|
| 73 | 69 | private final ObserveDataSourcesManager dataSourcesManager;
|
| 74 | 70 | private final Path storePath;
|
| 75 | 71 | private final List<BackupStorage> backups;
|
| 76 | 72 | private final BlockingDeque<BackupStorage> backupsToCheck = new LinkedBlockingDeque<>();
|
| 73 | + private final Gson gson;
|
|
| 77 | 74 | private boolean run = true;
|
| 78 | 75 | private final Thread checkBackups = new Thread("Check-Backups") {
|
| 79 | 76 | @Override
|
| ... | ... | @@ -121,16 +118,21 @@ public class BackupsManager implements Closeable { |
| 121 | 118 | |
| 122 | 119 | public BackupsManager(ClientConfig config, ObserveDataSourcesManager dataSourcesManager) {
|
| 123 | 120 | this.storePath = config.getBackupsFile().toPath();
|
| 124 | - this.backupsPath = config.getBackupDirectory().toPath();
|
|
| 125 | 121 | this.dataSourcesManager = dataSourcesManager;
|
| 126 | - |
|
| 122 | + this.gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateAdapter()).create();
|
|
| 127 | 123 | try {
|
| 128 | 124 | List<BackupStorage> backups;
|
| 129 | 125 | if (config.isBackupUse() && Files.exists(storePath)) {
|
| 130 | 126 | try (BufferedReader reader = Files.newBufferedReader(storePath, StandardCharsets.UTF_8)) {
|
| 131 | 127 | Type typeOfT = new TypeToken<List<BackupStorage>>() {
|
| 132 | 128 | }.getType();
|
| 133 | - backups = new Gson().fromJson(reader, typeOfT);
|
|
| 129 | + |
|
| 130 | + try {
|
|
| 131 | + backups = gson.fromJson(reader, typeOfT);
|
|
| 132 | + } catch (Exception e) {
|
|
| 133 | + log.error(String.format("Could not load %s file.", storePath), e);
|
|
| 134 | + backups = new LinkedList<>();
|
|
| 135 | + }
|
|
| 134 | 136 | log.info(String.format("Loaded %d backups from %s", backups.size(), storePath));
|
| 135 | 137 | }
|
| 136 | 138 | } else {
|
| ... | ... | @@ -160,36 +162,10 @@ public class BackupsManager implements Closeable { |
| 160 | 162 | }
|
| 161 | 163 | }
|
| 162 | 164 | |
| 163 | - private List<BackupStorage> discoverAutomaticBackups(Path backupsPath) throws IOException {
|
|
| 164 | - List<BackupStorage> backups = new ArrayList<>();
|
|
| 165 | - Files.walkFileTree(backupsPath, new SimpleFileVisitor<>() {
|
|
| 166 | - @Override
|
|
| 167 | - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
| 168 | - Matcher matcher = AUTOMATIC_BACKUP_FILENAME_PATTERN.matcher(file.toFile().getName());
|
|
| 169 | - if (matcher.matches()) {
|
|
| 170 | - BackupStorage backupStorage = new BackupStorage();
|
|
| 171 | - backupStorage.setDate(new Date(Files.getLastModifiedTime(file).toMillis()));
|
|
| 172 | - backupStorage.setFile(file.toFile());
|
|
| 173 | - backupStorage.setAutomatic(true);
|
|
| 174 | - backupStorage.setVerified(false);
|
|
| 175 | - backupStorage.setName(matcher.group(1));
|
|
| 176 | - backups.add(backupStorage);
|
|
| 177 | - }
|
|
| 178 | - return FileVisitResult.CONTINUE;
|
|
| 179 | - }
|
|
| 180 | - });
|
|
| 181 | - log.info(String.format("Discovered %d automatic backups from %s", backups.size(), backupsPath));
|
|
| 182 | - return backups;
|
|
| 183 | - }
|
|
| 184 | - |
|
| 185 | 165 | public List<BackupStorage> getAutomaticBackups() {
|
| 186 | 166 | return backups.stream().filter(BackupStorage::isAutomatic).sorted(Comparator.comparing(BackupStorage::getDate).reversed()).collect(Collectors.toList());
|
| 187 | 167 | }
|
| 188 | 168 | |
| 189 | - public List<BackupStorage> getUserBackups() {
|
|
| 190 | - return backups.stream().filter(BackupStorage::isUser).sorted(Comparator.comparing(BackupStorage::getDate).reversed()).collect(Collectors.toList());
|
|
| 191 | - }
|
|
| 192 | - |
|
| 193 | 169 | public void addAutomaticBackup(Path backupPath) {
|
| 194 | 170 | Matcher matcher = AUTOMATIC_BACKUP_FILENAME_PATTERN.matcher(backupPath.toFile().getName());
|
| 195 | 171 | if (!matcher.matches()) {
|
| ... | ... | @@ -204,21 +180,6 @@ public class BackupsManager implements Closeable { |
| 204 | 180 | backupsToCheck.add(backupStorage);
|
| 205 | 181 | }
|
| 206 | 182 | |
| 207 | - public void addUserBackup(Path backupPath) {
|
|
| 208 | - BackupStorage backupStorage = new BackupStorage();
|
|
| 209 | - backupStorage.setDate(new Date());
|
|
| 210 | - backupStorage.setFile(backupPath.toFile());
|
|
| 211 | - backupStorage.setAutomatic(false);
|
|
| 212 | - backupStorage.setVerified(false);
|
|
| 213 | - String name = Strings.removeEnd(backupPath.toFile().getName(), ".sql.gz");
|
|
| 214 | - backupStorage.setName(name);
|
|
| 215 | - backupsToCheck.add(backupStorage);
|
|
| 216 | - }
|
|
| 217 | - |
|
| 218 | - public void sanityBackups() {
|
|
| 219 | - log.info("Sanity backups at " + backupsPath);
|
|
| 220 | - }
|
|
| 221 | - |
|
| 222 | 183 | @Override
|
| 223 | 184 | public void close() {
|
| 224 | 185 | |
| ... | ... | @@ -239,7 +200,7 @@ public class BackupsManager implements Closeable { |
| 239 | 200 | private void storeBackups() throws IOException {
|
| 240 | 201 | log.info(String.format("Store %d backups to %s", backups.size(), storePath));
|
| 241 | 202 | try (BufferedWriter writer = Files.newBufferedWriter(storePath, StandardCharsets.UTF_8)) {
|
| 242 | - new Gson().toJson(backups, writer);
|
|
| 203 | + gson.toJson(backups, writer);
|
|
| 243 | 204 | }
|
| 244 | 205 | }
|
| 245 | 206 |
| ... | ... | @@ -406,6 +406,7 @@ public class ClientConfigUI extends JXTitledPanel implements WithClientUIContext |
| 406 | 406 | helper.addOption(ClientConfigOption.AVDTH_FORCE_IMPORT);
|
| 407 | 407 | |
| 408 | 408 | helper.addOption(ClientConfigOption.SHOW_SQL);
|
| 409 | + helper.addOption(ClientConfigOption.USE_JVM_KEY_STORE);
|
|
| 409 | 410 | |
| 410 | 411 | }
|
| 411 | 412 |
| ... | ... | @@ -170,6 +170,7 @@ observe.config.ui.tree.node.disabled.color=Color for disabled node |
| 170 | 170 | observe.config.ui.tree.node.empty.color=Color for empty node
|
| 171 | 171 | observe.config.ui.tree.node.unloaded.color=Color for unloaded node
|
| 172 | 172 | observe.config.ui.tree.node.unsaved.color=Color for unsaved node
|
| 173 | +observe.config.useJvmKeyStore.description=To use the Java «keystore», otherwise will use the embedded «keystore» (located at resources-xxx/observe.jks).
|
|
| 173 | 174 | observe.config.validation.lengthWeightEnable=Force validation of species length max
|
| 174 | 175 | observe.config.validation.speedEnable=Force validation of activities speed
|
| 175 | 176 | observe.config.validation.speedMaxValue=Max speed value used in activities speed validation
|
| ... | ... | @@ -283,6 +284,7 @@ observe.runner.copy.default.map.file=Création des cartes %1$s. |
| 283 | 284 | observe.runner.copy.default.report.file=Création du fichier de reports %1$s.
|
| 284 | 285 | observe.runner.copy.default.swing.preferences.file=Création du fichier de préférence Swing %1$s.
|
| 285 | 286 | observe.runner.copy.default.ui.file=Création du fichier de cosmétique %1$s.
|
| 287 | +observe.runner.copy.embedded.keystore.file=Copy embedded keystore (%s).
|
|
| 286 | 288 | observe.runner.i18n.loaded=Service de traduction chargé dans la langue %1$s.
|
| 287 | 289 | observe.runner.init=Initialisation d'ObServe %1$s %2$s
|
| 288 | 290 | observe.runner.initStorage.choice.createLocalStorage=Create local storage
|
| ... | ... | @@ -305,6 +307,7 @@ observe.runner.quit.without.ui=Close application without opening ui |
| 305 | 307 | observe.runner.start=Start ObServe %1$s %2$s
|
| 306 | 308 | observe.runner.title.error.dialog=An error occurs\!
|
| 307 | 309 | observe.runner.ui.loaded=Graphical interface is ready.
|
| 310 | +observe.runner.use.embedded.keystore.file=Use embedded keystore (%s).
|
|
| 308 | 311 | observe.runner.user.directories.loaded=User directory is ready (%1$s).
|
| 309 | 312 | observe.security.role=Role
|
| 310 | 313 | observe.security.role.administrator=Owner of database
|
| ... | ... | @@ -170,6 +170,7 @@ observe.config.ui.tree.node.disabled.color=Color for disabled node |
| 170 | 170 | observe.config.ui.tree.node.empty.color=Color for empty node
|
| 171 | 171 | observe.config.ui.tree.node.unloaded.color=Color for unloaded node
|
| 172 | 172 | observe.config.ui.tree.node.unsaved.color=Color for unsaved node
|
| 173 | +observe.config.useJvmKeyStore.description=To use the Java «keystore», otherwise will use the embedded «keystore» (located at resources-xxx/observe.jks). \#TODO
|
|
| 173 | 174 | observe.config.validation.lengthWeightEnable=Forzar la validación de la talla de especies min/max
|
| 174 | 175 | observe.config.validation.speedEnable=Forzar la validación de las velocidades de las actividades
|
| 175 | 176 | observe.config.validation.speedMaxValue=Velocidad máxima autorizada en el control de las velocidades de las actividades
|
| ... | ... | @@ -283,6 +284,7 @@ observe.runner.copy.default.map.file=Creación de los mapas %1$s. |
| 283 | 284 | observe.runner.copy.default.report.file=Creación del archivo de informes %1$s.
|
| 284 | 285 | observe.runner.copy.default.swing.preferences.file=Création du fichier de préférence Swing %1$s.
|
| 285 | 286 | observe.runner.copy.default.ui.file=Creación del archivo de cosmético %1$s.
|
| 287 | +observe.runner.copy.embedded.keystore.file=Copy embedded keystore (%s). \#TODO
|
|
| 286 | 288 | observe.runner.i18n.loaded=Servicio de traducción cargado en el idioma %1$s.
|
| 287 | 289 | observe.runner.init=Inicialización de ObServe %1$s %2$s
|
| 288 | 290 | observe.runner.initStorage.choice.createLocalStorage=Crear la base local
|
| ... | ... | @@ -305,6 +307,7 @@ observe.runner.quit.without.ui=Cierre de la aplicación sin abrir la interfaz gr |
| 305 | 307 | observe.runner.start=Inicio de ObServe %1$s %2$s
|
| 306 | 308 | observe.runner.title.error.dialog=Un error se ha producido\!
|
| 307 | 309 | observe.runner.ui.loaded=Finalizada la inicialización de la interfaz gráfica
|
| 310 | +observe.runner.use.embedded.keystore.file=Use embedded keystore (%s). \#TODO
|
|
| 308 | 311 | observe.runner.user.directories.loaded=Se ha inicializado el directorio del usuario (%1$s).
|
| 309 | 312 | observe.security.role=Rol
|
| 310 | 313 | observe.security.role.administrator=Propietario de la base
|
| ... | ... | @@ -170,6 +170,7 @@ observe.config.ui.tree.node.disabled.color=Couleur pour un nœud désactivé |
| 170 | 170 | observe.config.ui.tree.node.empty.color=Couleur pour un nœud vide
|
| 171 | 171 | observe.config.ui.tree.node.unloaded.color=Couleur pour un nœud non chargé
|
| 172 | 172 | observe.config.ui.tree.node.unsaved.color=Couleur pour un nœud non persisté
|
| 173 | +observe.config.useJvmKeyStore.description=Pour utiliser le «keystore» fourni par Java, sinon pour utiliser le keystore fourni par l'application (localisé ici \: resources-xxx/observe.jks).
|
|
| 173 | 174 | observe.config.validation.lengthWeightEnable=Forcer la validation des bornes min/max de taille d'espèce
|
| 174 | 175 | observe.config.validation.speedEnable=Forcer la validation des vitesses d'activités
|
| 175 | 176 | observe.config.validation.speedMaxValue=Vitesse maximale autorisée dans le contrôle des vitesses d'activités
|
| ... | ... | @@ -283,6 +284,7 @@ observe.runner.copy.default.map.file=Création des cartes %1$s. |
| 283 | 284 | observe.runner.copy.default.report.file=Création du fichier de reports %1$s.
|
| 284 | 285 | observe.runner.copy.default.swing.preferences.file=Création du fichier de préférence Swing %1$s.
|
| 285 | 286 | observe.runner.copy.default.ui.file=Création du fichier de cosmétique %1$s.
|
| 287 | +observe.runner.copy.embedded.keystore.file=Recopie du «keystore» embarqué par l'application (%s).
|
|
| 286 | 288 | observe.runner.i18n.loaded=Service de traduction chargé dans la langue %1$s.
|
| 287 | 289 | observe.runner.init=Initialisation d'ObServe %1$s %2$s
|
| 288 | 290 | observe.runner.initStorage.choice.createLocalStorage=Créer la base locale
|
| ... | ... | @@ -305,6 +307,7 @@ observe.runner.quit.without.ui=Fermeture de l'application sans ouvrir l'interfac |
| 305 | 307 | observe.runner.start=Démarrage d'ObServe %1$s %2$s
|
| 306 | 308 | observe.runner.title.error.dialog=Une erreur est survenue\!
|
| 307 | 309 | observe.runner.ui.loaded=Initialisation de l'interface graphique terminée.
|
| 310 | +observe.runner.use.embedded.keystore.file=Utilisation du «keystore» embarqué (%s).
|
|
| 308 | 311 | observe.runner.user.directories.loaded=Le répertoire utilisateur a été initialisé (%1$s).
|
| 309 | 312 | observe.security.role=Rôle
|
| 310 | 313 | observe.security.role.administrator=Propriétaire de la base
|