001/**
002 *
003 * Copyright 2017 Paul Schaub
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.omemo;
018
019/**
020 * Contains OMEMO related configuration options.
021 *
022 * @author Paul Schaub
023 */
024public final class OmemoConfiguration {
025
026    private static boolean IGNORE_READ_ONLY_DEVICES = true;
027    private static int MAX_READ_ONLY_MESSAGE_COUNT = 400;
028
029    /**
030     * Set to true, in order to ignore read-only devices.
031     *
032     * @param ignore ignore read-only devices
033     * @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>
034     */
035    public static void setIgnoreReadOnlyDevices(boolean ignore) {
036        IGNORE_READ_ONLY_DEVICES = ignore;
037    }
038
039    /**
040     * Return true, if the client should stop encrypting messages to a read-only device.
041     *
042     * @return true if read-only devices should get ignored after a certain amount of unanswered messages.
043     * @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>
044     */
045    public static boolean getIgnoreReadOnlyDevices() {
046        return IGNORE_READ_ONLY_DEVICES;
047    }
048
049    /**
050     * Set the maximum amount of messages that the client is allowed to send to a read-only device without getting a
051     * response. Once the message counter of a device reaches that value, the client will stop encrypting messages for
052     * the device (given that {@link #getIgnoreReadOnlyDevices()} is true).
053     * This threshold is used to prevent read-only devices from weakening forward secrecy.
054     *
055     * @param maxReadOnlyMessageCount maximum number of allowed messages to a read-only device.
056     * @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>
057     */
058    public static void setMaxReadOnlyMessageCount(int maxReadOnlyMessageCount) {
059        if (maxReadOnlyMessageCount <= 0) {
060            throw new IllegalArgumentException("maxReadOnlyMessageCount MUST be greater than 0.");
061        }
062        MAX_READ_ONLY_MESSAGE_COUNT = maxReadOnlyMessageCount;
063    }
064
065    /**
066     * Get the maximum amount of messages that the client is allowed to send to a read-only device without getting a
067     * response. Once the message counter of a device reaches that value, the client will stop encrypting messages for
068     * the device (given that {@link #getIgnoreReadOnlyDevices()} is true).
069     * This threshold is used to prevent read-only devices from weakening forward secrecy.
070     *
071     * @return maximum number of allowed messages to a read-only device.
072     * @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>
073     */
074    public static int getMaxReadOnlyMessageCount() {
075        return MAX_READ_ONLY_MESSAGE_COUNT;
076    }
077
078    /**
079     * Delete stale devices from the device list after a period of time.
080     */
081    private static boolean DELETE_STALE_DEVICES = true;
082    private static int DELETE_STALE_DEVICE_AFTER_HOURS = 24 * 7 * 4;     //4 weeks
083
084    public static void setDeleteStaleDevices(boolean delete) {
085        DELETE_STALE_DEVICES = delete;
086    }
087
088    public static boolean getDeleteStaleDevices() {
089        return DELETE_STALE_DEVICES;
090    }
091
092    public static void setDeleteStaleDevicesAfterHours(int hours) {
093        if (hours <= 0) {
094            throw new IllegalArgumentException("Hours must be greater than 0.");
095        }
096        DELETE_STALE_DEVICE_AFTER_HOURS = hours;
097    }
098
099    public static int getDeleteStaleDevicesAfterHours() {
100        return DELETE_STALE_DEVICE_AFTER_HOURS;
101    }
102
103    /**
104     * Upload a new signed prekey in intervals. This improves forward secrecy. Old keys are kept for some more time and
105     * then deleted.
106     */
107    private static boolean RENEW_OLD_SIGNED_PREKEYS = false;
108    private static int RENEW_OLD_SIGNED_PREKEYS_AFTER_HOURS = 24 * 7;    //One week
109    private static int MAX_NUMBER_OF_STORED_SIGNED_PREKEYS = 4;
110
111    /**
112     * Decide, whether signed preKeys are automatically rotated or not.
113     * It is highly recommended to rotate signed preKeys to preserve forward secrecy.
114     *
115     * @param renew automatically rotate signed preKeys?
116     */
117    public static void setRenewOldSignedPreKeys(boolean renew) {
118        RENEW_OLD_SIGNED_PREKEYS = renew;
119    }
120
121    /**
122     * Determine, whether signed preKeys are automatically rotated or not.
123     *
124     * @return auto-rotate signed preKeys?
125     */
126    public static boolean getRenewOldSignedPreKeys() {
127        return RENEW_OLD_SIGNED_PREKEYS;
128    }
129
130    /**
131     * Set the interval in hours, after which the published signed preKey should be renewed.
132     * This value should be between one or two weeks.
133     *
134     * @param hours hours after which signed preKeys should be rotated.
135     */
136    public static void setRenewOldSignedPreKeysAfterHours(int hours) {
137        if (hours <= 0) {
138            throw new IllegalArgumentException("Hours must be greater than 0.");
139        }
140        RENEW_OLD_SIGNED_PREKEYS_AFTER_HOURS = hours;
141    }
142
143    /**
144     * Get the interval in hours, after which the published signed preKey should be renewed.
145     * This value should be between one or two weeks.
146     *
147     * @return hours after which signed preKeys should be rotated.
148     */
149    public static int getRenewOldSignedPreKeysAfterHours() {
150        return RENEW_OLD_SIGNED_PREKEYS_AFTER_HOURS;
151    }
152
153    /**
154     * Set the maximum number of signed preKeys that are cached until the oldest one gets deleted.
155     * This number should not be too small in order to prevent message loss, but also not too big
156     * to preserve forward secrecy.
157     *
158     * @param number number of cached signed preKeys.
159     */
160    public static void setMaxNumberOfStoredSignedPreKeys(int number) {
161        if (number <= 0) {
162            throw new IllegalArgumentException("Number must be greater than 0.");
163        }
164        MAX_NUMBER_OF_STORED_SIGNED_PREKEYS = number;
165    }
166
167    /**
168     * Return the maximum number of signed preKeys that are cached until the oldest one gets deleted.
169     * @return max number of cached signed preKeys.
170     */
171    public static int getMaxNumberOfStoredSignedPreKeys() {
172        return MAX_NUMBER_OF_STORED_SIGNED_PREKEYS;
173    }
174
175    /**
176     * Add a plaintext body hint about omemo encryption to the message.
177     */
178    private static boolean ADD_OMEMO_HINT_BODY = true;
179
180    /**
181     * Decide, whether an OMEMO message should carry a plaintext hint about OMEMO encryption.
182     * Eg. "I sent you an OMEMO encrypted message..."
183     *
184     * @param addHint shall we add a hint?
185     */
186    public static void setAddOmemoHintBody(boolean addHint) {
187        ADD_OMEMO_HINT_BODY = addHint;
188    }
189
190    /**
191     * Determine, whether an OMEMO message should carry a plaintext hint about OMEMO encryption.
192     *
193     * @return true, if a hint is added to the message.
194     */
195    public static boolean getAddOmemoHintBody() {
196        return ADD_OMEMO_HINT_BODY;
197    }
198
199    private static boolean REPAIR_BROKEN_SESSIONS_WITH_PREKEY_MESSAGES = true;
200
201    /**
202     * Determine, whether incoming messages, which have broken sessions should automatically be answered by an empty
203     * preKeyMessage in order to establish a new session.
204     *
205     * @return true if session should be repaired automatically.
206     */
207    public static boolean getRepairBrokenSessionsWithPreKeyMessages() {
208        return REPAIR_BROKEN_SESSIONS_WITH_PREKEY_MESSAGES;
209    }
210
211    /**
212     * Decide, whether incoming messages, which have broken sessions should automatically be answered by an empty
213     * preKeyMessage in order to establish a new session.
214     *
215     * @param repair repair sessions?
216     */
217    public static void setRepairBrokenSessionsWithPrekeyMessages(boolean repair) {
218        REPAIR_BROKEN_SESSIONS_WITH_PREKEY_MESSAGES = repair;
219    }
220
221    private static boolean COMPLETE_SESSION_WITH_EMPTY_MESSAGE = true;
222
223    /**
224     * Determine, whether incoming preKeyMessages should automatically be answered by an empty message in order to
225     * complete the session.
226     *
227     * @return true if sessions should be completed.
228     */
229    public static boolean getCompleteSessionWithEmptyMessage() {
230        return COMPLETE_SESSION_WITH_EMPTY_MESSAGE;
231    }
232
233    /**
234     * Decide, whether incoming preKeyMessages should automatically be answered by an empty message in order to
235     * complete the session.
236     *
237     * @param complete complete the session or not
238     */
239    public static void setCompleteSessionWithEmptyMessage(boolean complete) {
240        COMPLETE_SESSION_WITH_EMPTY_MESSAGE = complete;
241    }
242}