OmemoConfiguration.java
/**
*
* Copyright 2017 Paul Schaub
*
* 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.smackx.omemo;
/**
* Contains OMEMO related configuration options.
*
* @author Paul Schaub
*/
public final class OmemoConfiguration {
private static boolean IGNORE_READ_ONLY_DEVICES = true;
private static int MAX_READ_ONLY_MESSAGE_COUNT = 400;
/**
* Set to true, in order to ignore read-only devices.
*
* @param ignore ignore read-only devices
* @see <a href="https://blog.jabberhead.tk/2019/12/13/pitfalls-for-omemo-implementations-part-1-inactive-devices/">Blog Post explaining the danger of read-only devices.</a>
*/
public static void setIgnoreReadOnlyDevices(boolean ignore) {
IGNORE_READ_ONLY_DEVICES = ignore;
}
/**
* Return true, if the client should stop encrypting messages to a read-only device.
*
* @return true if read-only devices should get ignored after a certain amount of unanswered messages.
* @see <a href="https://blog.jabberhead.tk/2019/12/13/pitfalls-for-omemo-implementations-part-1-inactive-devices/">Blog Post explaining the danger of read-only devices.</a>
*/
public static boolean getIgnoreReadOnlyDevices() {
return IGNORE_READ_ONLY_DEVICES;
}
/**
* Set the maximum amount of messages that the client is allowed to send to a read-only device without getting a
* response. Once the message counter of a device reaches that value, the client will stop encrypting messages for
* the device (given that {@link #getIgnoreReadOnlyDevices()} is true).
* This threshold is used to prevent read-only devices from weakening forward secrecy.
*
* @param maxReadOnlyMessageCount maximum number of allowed messages to a read-only device.
* @see <a href="https://blog.jabberhead.tk/2019/12/13/pitfalls-for-omemo-implementations-part-1-inactive-devices/">Blog Post explaining the danger of read-only devices.</a>
*/
public static void setMaxReadOnlyMessageCount(int maxReadOnlyMessageCount) {
if (maxReadOnlyMessageCount <= 0) {
throw new IllegalArgumentException("maxReadOnlyMessageCount MUST be greater than 0.");
}
MAX_READ_ONLY_MESSAGE_COUNT = maxReadOnlyMessageCount;
}
/**
* Get the maximum amount of messages that the client is allowed to send to a read-only device without getting a
* response. Once the message counter of a device reaches that value, the client will stop encrypting messages for
* the device (given that {@link #getIgnoreReadOnlyDevices()} is true).
* This threshold is used to prevent read-only devices from weakening forward secrecy.
*
* @return maximum number of allowed messages to a read-only device.
* @see <a href="https://blog.jabberhead.tk/2019/12/13/pitfalls-for-omemo-implementations-part-1-inactive-devices/">Blog Post explaining the danger of read-only devices.</a>
*/
public static int getMaxReadOnlyMessageCount() {
return MAX_READ_ONLY_MESSAGE_COUNT;
}
/**
* Delete stale devices from the device list after a period of time.
*/
private static boolean DELETE_STALE_DEVICES = true;
private static int DELETE_STALE_DEVICE_AFTER_HOURS = 24 * 7 * 4; //4 weeks
public static void setDeleteStaleDevices(boolean delete) {
DELETE_STALE_DEVICES = delete;
}
public static boolean getDeleteStaleDevices() {
return DELETE_STALE_DEVICES;
}
public static void setDeleteStaleDevicesAfterHours(int hours) {
if (hours <= 0) {
throw new IllegalArgumentException("Hours must be greater than 0.");
}
DELETE_STALE_DEVICE_AFTER_HOURS = hours;
}
public static int getDeleteStaleDevicesAfterHours() {
return DELETE_STALE_DEVICE_AFTER_HOURS;
}
/**
* Upload a new signed prekey in intervals. This improves forward secrecy. Old keys are kept for some more time and
* then deleted.
*/
private static boolean RENEW_OLD_SIGNED_PREKEYS = false;
private static int RENEW_OLD_SIGNED_PREKEYS_AFTER_HOURS = 24 * 7; //One week
private static int MAX_NUMBER_OF_STORED_SIGNED_PREKEYS = 4;
/**
* Decide, whether signed preKeys are automatically rotated or not.
* It is highly recommended to rotate signed preKeys to preserve forward secrecy.
*
* @param renew automatically rotate signed preKeys?
*/
public static void setRenewOldSignedPreKeys(boolean renew) {
RENEW_OLD_SIGNED_PREKEYS = renew;
}
/**
* Determine, whether signed preKeys are automatically rotated or not.
*
* @return auto-rotate signed preKeys?
*/
public static boolean getRenewOldSignedPreKeys() {
return RENEW_OLD_SIGNED_PREKEYS;
}
/**
* Set the interval in hours, after which the published signed preKey should be renewed.
* This value should be between one or two weeks.
*
* @param hours hours after which signed preKeys should be rotated.
*/
public static void setRenewOldSignedPreKeysAfterHours(int hours) {
if (hours <= 0) {
throw new IllegalArgumentException("Hours must be greater than 0.");
}
RENEW_OLD_SIGNED_PREKEYS_AFTER_HOURS = hours;
}
/**
* Get the interval in hours, after which the published signed preKey should be renewed.
* This value should be between one or two weeks.
*
* @return hours after which signed preKeys should be rotated.
*/
public static int getRenewOldSignedPreKeysAfterHours() {
return RENEW_OLD_SIGNED_PREKEYS_AFTER_HOURS;
}
/**
* Set the maximum number of signed preKeys that are cached until the oldest one gets deleted.
* This number should not be too small in order to prevent message loss, but also not too big
* to preserve forward secrecy.
*
* @param number number of cached signed preKeys.
*/
public static void setMaxNumberOfStoredSignedPreKeys(int number) {
if (number <= 0) {
throw new IllegalArgumentException("Number must be greater than 0.");
}
MAX_NUMBER_OF_STORED_SIGNED_PREKEYS = number;
}
/**
* Return the maximum number of signed preKeys that are cached until the oldest one gets deleted.
* @return max number of cached signed preKeys.
*/
public static int getMaxNumberOfStoredSignedPreKeys() {
return MAX_NUMBER_OF_STORED_SIGNED_PREKEYS;
}
/**
* Add a plaintext body hint about omemo encryption to the message.
*/
private static boolean ADD_OMEMO_HINT_BODY = true;
/**
* Decide, whether an OMEMO message should carry a plaintext hint about OMEMO encryption.
* Eg. "I sent you an OMEMO encrypted message..."
*
* @param addHint shall we add a hint?
*/
public static void setAddOmemoHintBody(boolean addHint) {
ADD_OMEMO_HINT_BODY = addHint;
}
/**
* Determine, whether an OMEMO message should carry a plaintext hint about OMEMO encryption.
*
* @return true, if a hint is added to the message.
*/
public static boolean getAddOmemoHintBody() {
return ADD_OMEMO_HINT_BODY;
}
private static boolean REPAIR_BROKEN_SESSIONS_WITH_PREKEY_MESSAGES = true;
/**
* Determine, whether incoming messages, which have broken sessions should automatically be answered by an empty
* preKeyMessage in order to establish a new session.
*
* @return true if session should be repaired automatically.
*/
public static boolean getRepairBrokenSessionsWithPreKeyMessages() {
return REPAIR_BROKEN_SESSIONS_WITH_PREKEY_MESSAGES;
}
/**
* Decide, whether incoming messages, which have broken sessions should automatically be answered by an empty
* preKeyMessage in order to establish a new session.
*
* @param repair repair sessions?
*/
public static void setRepairBrokenSessionsWithPrekeyMessages(boolean repair) {
REPAIR_BROKEN_SESSIONS_WITH_PREKEY_MESSAGES = repair;
}
private static boolean COMPLETE_SESSION_WITH_EMPTY_MESSAGE = true;
/**
* Determine, whether incoming preKeyMessages should automatically be answered by an empty message in order to
* complete the session.
*
* @return true if sessions should be completed.
*/
public static boolean getCompleteSessionWithEmptyMessage() {
return COMPLETE_SESSION_WITH_EMPTY_MESSAGE;
}
/**
* Decide, whether incoming preKeyMessages should automatically be answered by an empty message in order to
* complete the session.
*
* @param complete complete the session or not
*/
public static void setCompleteSessionWithEmptyMessage(boolean complete) {
COMPLETE_SESSION_WITH_EMPTY_MESSAGE = complete;
}
}