diff --git a/cms-core/pom.xml b/cms-core/pom.xml index 2ded86422..5ecbbb5cb 100644 --- a/cms-core/pom.xml +++ b/cms-core/pom.xml @@ -28,6 +28,11 @@ jtoml-serializer-gson 1.3.0 + + io.github.cdimascio + dotenv-java + 3.2.0 + org.simplejavamail simple-java-mail diff --git a/cms-core/src/main/java/com/condation/cms/core/configuration/ConfigurationFactory.java b/cms-core/src/main/java/com/condation/cms/core/configuration/ConfigurationFactory.java index 3818c0152..4ee5dcae2 100644 --- a/cms-core/src/main/java/com/condation/cms/core/configuration/ConfigurationFactory.java +++ b/cms-core/src/main/java/com/condation/cms/core/configuration/ConfigurationFactory.java @@ -30,6 +30,7 @@ import com.condation.cms.core.configuration.configs.TaxonomyConfiguration; import com.condation.cms.core.configuration.reload.CronReload; import com.condation.cms.core.configuration.reload.NoReload; +import com.condation.cms.core.configuration.source.EnvConfigSource; import com.condation.cms.core.configuration.source.TomlConfigSource; import com.condation.cms.core.configuration.source.YamlConfigSource; import java.io.IOException; @@ -110,6 +111,7 @@ private static SimpleConfiguration serverConfiguration(EventBus eventBus) throws return SimpleConfiguration.builder(eventBus) .id("server") .reloadStrategy(new NoReload()) + .addSource(new EnvConfigSource()) .addSource(TomlConfigSource.build(ServerUtil.getPath("server.toml"))) .addSource(YamlConfigSource.build(ServerUtil.getPath("server.yaml"))) .build(); diff --git a/cms-core/src/main/java/com/condation/cms/core/configuration/source/EnvConfigSource.java b/cms-core/src/main/java/com/condation/cms/core/configuration/source/EnvConfigSource.java new file mode 100644 index 000000000..595f71077 --- /dev/null +++ b/cms-core/src/main/java/com/condation/cms/core/configuration/source/EnvConfigSource.java @@ -0,0 +1,77 @@ +package com.condation.cms.core.configuration.source; + +/*- + * #%L + * cms-core + * %% + * Copyright (C) 2023 - 2025 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.api.utils.MapUtil; +import com.condation.cms.api.utils.ServerUtil; +import com.condation.cms.core.configuration.ConfigSource; +import com.condation.cms.core.utils.EnvUtil; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class EnvConfigSource implements ConfigSource { + + private final Map envVariables; + + public EnvConfigSource () { + this(ServerUtil.getHome().toAbsolutePath().toString()); + } + + public EnvConfigSource(String path) { + this.envVariables = EnvUtil.load(path); + } + + @Override + public boolean reload() { + // Environment variables are not expected to change during runtime + return false; + } + + @Override + public boolean exists() { + // Environment variables are always considered to exist + return true; + } + + @Override + public String getString(String field) { + return (String) MapUtil.getValue(envVariables, field); + } + + @Override + public Object get(String field) { + return MapUtil.getValue(envVariables, field); + } + + @Override + public Map getMap(String field) { + return MapUtil.getValue(envVariables, field, Collections.emptyMap()); + } + + @Override + public List getList(String field) { + return MapUtil.getValue(envVariables, field, Collections.emptyList()); + } +} diff --git a/cms-core/src/main/java/com/condation/cms/core/utils/EnvUtil.java b/cms-core/src/main/java/com/condation/cms/core/utils/EnvUtil.java new file mode 100644 index 000000000..5545a7c08 --- /dev/null +++ b/cms-core/src/main/java/com/condation/cms/core/utils/EnvUtil.java @@ -0,0 +1,84 @@ +package com.condation.cms.core.utils; + +/*- + * #%L + * cms-core + * %% + * Copyright (C) 2023 - 2025 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public + * License along with this program. If not, see + * . + * #L% + */ + +import io.github.cdimascio.dotenv.Dotenv; +import java.util.HashMap; +import java.util.Map; + +public class EnvUtil { + + public static Map load(String path) { + Map envMap = new HashMap<>(); + + // Load .env file if it exists + Dotenv dotenv = Dotenv.configure().directory(path).ignoreIfMissing().load(); + dotenv.entries().forEach(entry -> { + String key = entry.getKey(); + String value = entry.getValue(); + addValueToMap(envMap, key, value); + }); + + // Load system environment variables, overriding .env variables + System.getenv().forEach((key, value) -> { + addValueToMap(envMap, key, value); + }); + + // Load system properties, overriding system environment variables + System.getProperties().forEach((key, value) -> { + addValueToMap(envMap, (String) key, (String) value); + }); + + return envMap; + } + + private static void addValueToMap(Map map, String key, String value) { + if (key == null || key.trim().isEmpty()) { + return; + } + String[] parts = key.split("_"); + if (parts.length == 0) { + return; + } + + Map currentMap = map; + for (int i = 0; i < parts.length - 1; i++) { + String part = parts[i].toLowerCase(); + if (part.isEmpty()) { + continue; + } + Object node = currentMap.get(part); + if (node instanceof Map) { + currentMap = (Map) node; + } else if (node == null) { + Map newMap = new HashMap<>(); + currentMap.put(part, newMap); + currentMap = newMap; + } else { + // A value is already present, cannot create a map here. + return; + } + } + currentMap.put(parts[parts.length - 1].toLowerCase(), value); + } +} diff --git a/test-server/.env b/test-server/.env new file mode 100644 index 000000000..f8eae0f83 --- /dev/null +++ b/test-server/.env @@ -0,0 +1 @@ +UI_SECRET=super-secret-token \ No newline at end of file diff --git a/test-server/server.toml b/test-server/server.toml index a6393c408..59d27dce2 100644 --- a/test-server/server.toml +++ b/test-server/server.toml @@ -4,8 +4,6 @@ env = "dev" port = 2020 ip = "127.0.0.1" -[ui] -secret = "super-secret-token" [ipc] port = 6868