/* * Copyright (C) 2004-2008 Jive Software, 2017-2025 Ignite Realtime Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.util; import org.apache.commons.lang3.StringUtils; import org.jivesoftware.database.DbConnectionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.text.DateFormat; import java.util.*; import java.util.Map.Entry; /** * Controls Jive properties. Jive properties are only meant to be set and retrieved * by core Jive classes. Some properties may be stored in XML format while others in the * database.
* * When starting up the application this class needs to be configured so that the initial * configuration of the application may be loaded from the configuration file. The configuration * file holds properties stored in XML format, database configuration and user authentication * configuration. Use {@link #setHomePath(Path)} and {@link #setConfigName(String)} for * setting the home directory and path to the configuration file.
*
* XML property names must be in the form prop.name - parts of the name must
* be separated by ".". The value can be any valid String, including strings with line breaks.
*/
public class JiveGlobals {
private static final Logger Log = LoggerFactory.getLogger(JiveGlobals.class);
private static String JIVE_CONFIG_FILENAME = "conf" + File.separator + "openfire.xml";
private static final String JIVE_SECURITY_FILENAME = "conf" + File.separator + "security.xml";
private static final String ENCRYPTED_PROPERTY_NAME_PREFIX = "encrypt.";
private static final String ENCRYPTED_PROPERTY_NAMES = ENCRYPTED_PROPERTY_NAME_PREFIX + "property.name";
private static final String ENCRYPTION_ALGORITHM = ENCRYPTED_PROPERTY_NAME_PREFIX + "algorithm";
private static final String ENCRYPTION_KEY_CURRENT = ENCRYPTED_PROPERTY_NAME_PREFIX + "key.current";
private static final String ENCRYPTION_KEY_NEW = ENCRYPTED_PROPERTY_NAME_PREFIX + "key.new";
private static final String ENCRYPTION_KEY_OLD = ENCRYPTED_PROPERTY_NAME_PREFIX + "key.old";
private static final String ENCRYPTION_ALGORITHM_AES = "AES";
private static final String ENCRYPTION_ALGORITHM_BLOWFISH = "Blowfish";
private static final String BLOWFISH_KDF = ENCRYPTED_PROPERTY_NAME_PREFIX + "blowfish.kdf";
private static final String BLOWFISH_SALT = ENCRYPTED_PROPERTY_NAME_PREFIX + "blowfish.salt";
/** Blowfish key derivation function using PBKDF2-HMAC-SHA512 */
public static final String BLOWFISH_KDF_PBKDF2 = "pbkdf2";
/** Blowfish key derivation function using legacy SHA1 (for backward compatibility) */
public static final String BLOWFISH_KDF_SHA1 = "sha1";
/**
* Location of the jiveHome directory. All configuration files should be
* located here.
*/
private static Path home = null;
private static boolean failedLoading = false;
private static XMLProperties openfireProperties = null;
private static XMLProperties securityProperties = null;
private static JiveProperties properties = null;
private static Locale locale = null;
private static TimeZone timeZone = null;
private static DateFormat dateFormat = null;
private static DateFormat dateTimeFormat = null;
private static DateFormat timeFormat = null;
private static Encryptor propertyEncryptor = null;
private static Encryptor propertyEncryptorNew = null;
private static String currentKey = null;
/**
* Returns the global Locale used by Jive. A locale specifies language
* and country codes, and is used for internationalization. The default
* locale is system dependent - Locale.getDefault().
*
* @return the global locale used by Jive.
*/
public static Locale getLocale() {
if (locale == null) {
if (openfireProperties != null) {
String [] localeArray;
String localeProperty = openfireProperties.getProperty("locale");
if (localeProperty != null) {
localeArray = localeProperty.split("_");
}
else {
localeArray = new String[] {"", ""};
}
String language = localeArray[0];
if (language == null) {
language = "";
}
String country = "";
if (localeArray.length == 2) {
country = localeArray[1];
}
// If no locale info is specified, return the system default Locale.
if (language.isEmpty() && country.isEmpty()) {
locale = Locale.getDefault();
}
else {
locale = new Locale(language, country);
}
}
else {
return Locale.getDefault();
}
}
return locale;
}
/**
* Sets the global locale used by Jive. A locale specifies language
* and country codes, and is used for formatting dates and numbers.
* The default locale is Locale.US.
*
* @param newLocale the global Locale for Jive.
*/
public static void setLocale(Locale newLocale) {
locale = newLocale;
// Save values to Jive properties.
setXMLProperty("locale", locale.toString());
// Reset the date formatter objects
timeFormat = null;
dateFormat = null;
dateTimeFormat = null;
}
/**
* Returns the global TimeZone used by Jive. The default is the VM's
* default time zone.
*
* @return the global time zone used by Jive.
*/
public static TimeZone getTimeZone() {
if (timeZone == null) {
if (properties != null) {
String timeZoneID = properties.get("locale.timeZone");
if (timeZoneID == null) {
timeZone = TimeZone.getDefault();
}
else {
timeZone = TimeZone.getTimeZone(timeZoneID);
}
}
else {
return TimeZone.getDefault();
}
}
return timeZone;
}
/**
* Sets the global time zone used by Jive. The default time zone is the VM's
* time zone.
*
* @param newTimeZone Time zone to set.
*/
public static void setTimeZone(TimeZone newTimeZone) {
timeZone = newTimeZone;
if (timeFormat != null) {
timeFormat.setTimeZone(timeZone);
}
if (dateFormat != null) {
dateFormat.setTimeZone(timeZone);
}
if (dateTimeFormat != null) {
dateTimeFormat.setTimeZone(timeZone);
}
setProperty("locale.timeZone", timeZone.getID());
}
/**
* Formats a Date object to return a time using the global locale.
*
* @param date the Date to format.
* @return a String representing the time.
*/
public static String formatTime(Date date) {
if (timeFormat == null) {
if (properties != null) {
timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, getLocale());
timeFormat.setTimeZone(getTimeZone());
}
else {
DateFormat instance = DateFormat.getTimeInstance(DateFormat.SHORT, getLocale());
instance.setTimeZone(getTimeZone());
return instance.format(date);
}
}
return timeFormat.format(date);
}
/**
* Formats a Date object to return a date using the global locale.
*
* @param date the Date to format.
* @return a String representing the date.
*/
public static String formatDate(Date date) {
if (dateFormat == null) {
if (properties != null) {
dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale());
dateFormat.setTimeZone(getTimeZone());
}
else {
DateFormat instance = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale());
instance.setTimeZone(getTimeZone());
return instance.format(date);
}
}
return dateFormat.format(date);
}
/**
* Formats a Date object to return a date and time using the global locale.
*
* @param date the Date to format.
* @return a String representing the date and time.
*/
public static String formatDateTime(Date date) {
if (dateTimeFormat == null) {
if (properties != null) {
dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.MEDIUM, getLocale());
dateTimeFormat.setTimeZone(getTimeZone());
}
else {
DateFormat instance = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.MEDIUM, getLocale());
instance.setTimeZone(getTimeZone());
return instance.format(date);
}
}
return dateTimeFormat.format(date);
}
/**
* Returns the location of the home directory.
*
* @return the location of the home dir.
*/
public static Path getHomePath() {
if (openfireProperties == null) {
loadOpenfireProperties();
}
return home;
}
/**
* Sets the location of the home directory. The directory must exist and the
* user running the application must have read and write permissions over the specified
* directory.
*
* @param homeDir the location of the home dir.
*/
public static void setHomePath(Path homeDir) {
// Do a permission check on the new home directory
if (!Files.exists(homeDir) || !Files.isDirectory(homeDir)) {
Log.error("Error - the specified home directory does not exist or is not a directory (" + homeDir + ")");
}
else if (!Files.isReadable(homeDir) || !Files.isWritable(homeDir)) {
Log.error("Error - the user running this application can not read " +
"and write to the specified home directory (" + homeDir + "). " +
"Please grant the executing user read and write permissions.");
}
else {
home = homeDir.normalize().toAbsolutePath();
}
}
/**
* Returns a local property. Local properties are stored in the file defined in
* {@code JIVE_CONFIG_FILENAME} that exists in the {@code home} directory.
* Properties are always specified as "foo.bar.prop", which would map to
* the following entry in the XML file:
*
* <foo>
* <bar>
* <prop>some value</prop>
* </bar>
* </foo>
*
*
* @param name the name of the property to return.
* @return the property value specified by name.
*/
public static String getXMLProperty(String name) {
if (openfireProperties == null) {
loadOpenfireProperties();
}
return openfireProperties.getProperty(name);
}
/**
* Returns a local property. Local properties are stored in the file defined in
* {@code JIVE_CONFIG_FILENAME} that exists in the {@code home} directory.
* Properties are always specified as "foo.bar.prop", which would map to
* the following entry in the XML file:
*
* <foo>
* <bar>
* <prop>some value</prop>
* </bar>
* </foo>
*
*
* If the specified property can't be found, the {@code defaultValue} will be returned.
*
* @param name the name of the property to return.
* @param defaultValue the default value for the property.
* @return the property value specified by name.
*/
public static String getXMLProperty(String name, String defaultValue) {
if (openfireProperties == null) {
loadOpenfireProperties();
}
String value = openfireProperties.getProperty(name);
if (value == null) {
value = defaultValue;
}
return value;
}
/**
* Returns an integer value local property. Local properties are stored in the file defined in
* {@code JIVE_CONFIG_FILENAME} that exists in the {@code home} directory.
* Properties are always specified as "foo.bar.prop", which would map to
* the following entry in the XML file:
*
* <foo>
* <bar>
* <prop>some value</prop>
* </bar>
* </foo>
*
*
* If the specified property can't be found, or if the value is not a number, the
* {@code defaultValue} will be returned.
*
* @param name the name of the property to return.
* @param defaultValue value returned if the property could not be loaded or was not
* a number.
* @return the property value specified by name or {@code defaultValue}.
*/
public static int getXMLProperty(String name, int defaultValue) {
String value = getXMLProperty(name);
if (value != null) {
try {
return Integer.parseInt(value);
}
catch (NumberFormatException nfe) {
// Ignore.
}
}
return defaultValue;
}
/**
* Returns a boolean value local property. Local properties are stored in the
* file defined in {@code JIVE_CONFIG_FILENAME} that exists in the {@code home}
* directory. Properties are always specified as "foo.bar.prop", which would map to
* the following entry in the XML file:
*
* <foo>
* <bar>
* <prop>some value</prop>
* </bar>
* </foo>
*
*
* If the specified property can't be found, the {@code defaultValue} will be returned.
* If the property is found, it will be parsed using {@link Boolean#valueOf(String)}.
*
* @param name the name of the property to return.
* @param defaultValue value returned if the property could not be loaded or was not
* a number.
* @return the property value specified by name or {@code defaultValue}.
*/
public static boolean getXMLProperty(String name, boolean defaultValue) {
String value = getXMLProperty(name);
if (value != null) {
return Boolean.parseBoolean(value);
}
return defaultValue;
}
/**
* Sets a local property. If the property doesn't already exists, a new
* one will be created. Local properties are stored in the file defined in
* {@code JIVE_CONFIG_FILENAME} that exists in the {@code home} directory.
* Properties are always specified as "foo.bar.prop", which would map to
* the following entry in the XML file:
*
* <foo>
* <bar>
* <prop>some value</prop>
* </bar>
* </foo>
*
*
* @param name the name of the property being set.
* @param value the value of the property being set.
* @return {@code true} if the property was correctly saved to file, otherwise {@code false}
*/
public static boolean setXMLProperty(String name, String value) {
if (openfireProperties == null) {
loadOpenfireProperties();
}
return openfireProperties.setProperty(name, value);
}
/**
* Sets multiple local properties at once. If a property doesn't already exists, a new
* one will be created. Local properties are stored in the file defined in
* {@code JIVE_CONFIG_FILENAME} that exists in the {@code home} directory.
* Properties are always specified as "foo.bar.prop", which would map to
* the following entry in the XML file:
*
* <foo>
* <bar>
* <prop>some value</prop>
* </bar>
* </foo>
*
*
* @param propertyMap a map of properties, keyed on property name.
*/
public static void setXMLProperties(Map* * Local properties are stored in the file defined in {@code JIVE_CONFIG_FILENAME} that exists * in the {@code home} directory. Properties are always specified as "foo.bar.prop", * which would map to the following entry in the XML file: *
* <foo>
* <bar>
* <prop>some value</prop>
* </bar>
* </foo>
*
*
*
* @param parent the name of the parent property to return the children for.
* @return all child property values for the given parent.
*/
public static List
*
* @param parent Parent "node" to find the children of.
* @return a List of all immediate children property names (Strings).
*/
public static List
*
* @param parent the name of the parent property to return the children for.
* @return all child property values for the given parent.
*/
public static List