Smack/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/FileBasedOmemoStore.java

942 lines
32 KiB
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;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.internal.CachedDeviceList;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jxmpp.jid.BareJid;
/**
* Like a rocket!
*
* @author Paul Schaub
*/
public abstract class FileBasedOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>
extends OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph> {
private static final Logger LOGGER = Logger.getLogger(FileBasedOmemoStore.class.getSimpleName());
private final FileHierarchy hierarchy;
public FileBasedOmemoStore() {
this(OmemoConfiguration.getFileBasedOmemoStoreDefaultPath());
}
public FileBasedOmemoStore(File basePath) {
super();
if (basePath == null) {
throw new IllegalStateException("No FileBasedOmemoStoreDefaultPath set in OmemoConfiguration.");
}
this.hierarchy = new FileHierarchy(basePath);
}
@Override
public boolean isFreshInstallation(OmemoManager omemoManager) {
File userDirectory = hierarchy.getUserDeviceDirectory(omemoManager);
File[] files = userDirectory.listFiles();
return files == null || files.length == 0;
}
@Override
public int getDefaultDeviceId(BareJid user) {
try {
return readInt(hierarchy.getDefaultDeviceIdPath(user));
} catch (IOException e) {
return -1;
}
}
@Override
public void setDefaultDeviceId(BareJid user, int defaultDeviceId) {
File defaultDeviceIdPath = hierarchy.getDefaultDeviceIdPath(user);
if (defaultDeviceIdPath == null) {
LOGGER.log(Level.SEVERE, "defaultDeviceIdPath is null!");
}
try {
writeInt(defaultDeviceIdPath, defaultDeviceId);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write defaultDeviceId: " + e, e);
}
}
@Override
public int loadLastPreKeyId(OmemoManager omemoManager) {
try {
int l = readInt(hierarchy.getLastPreKeyIdPath(omemoManager));
return l == -1 ? 0 : l;
} catch (IOException e) {
return 0;
}
}
@Override
public void storeLastPreKeyId(OmemoManager omemoManager, int currentPreKeyId) {
try {
writeInt(hierarchy.getLastPreKeyIdPath(omemoManager), currentPreKeyId);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write lastPreKeyId: " + e, e);
}
}
@Override
public T_IdKeyPair loadOmemoIdentityKeyPair(OmemoManager omemoManager) throws CorruptedOmemoKeyException {
File identityKeyPairPath = hierarchy.getIdentityKeyPairPath(omemoManager);
try {
byte[] bytes = readBytes(identityKeyPairPath);
return bytes != null ? keyUtil().identityKeyPairFromBytes(bytes) : null;
} catch (IOException e) {
return null;
}
}
@Override
public void storeOmemoIdentityKeyPair(OmemoManager omemoManager, T_IdKeyPair identityKeyPair) {
File identityKeyPairPath = hierarchy.getIdentityKeyPairPath(omemoManager);
try {
writeBytes(identityKeyPairPath, keyUtil().identityKeyPairToBytes(identityKeyPair));
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write omemoIdentityKeyPair: " + e, e);
}
}
@Override
public T_IdKey loadOmemoIdentityKey(OmemoManager omemoManager, OmemoDevice device) throws CorruptedOmemoKeyException {
File identityKeyPath = hierarchy.getContactsIdentityKeyPath(omemoManager, device);
try {
byte[] bytes = readBytes(identityKeyPath);
return bytes != null ? keyUtil().identityKeyFromBytes(bytes) : null;
} catch (IOException e) {
return null;
}
}
@Override
public void storeOmemoIdentityKey(OmemoManager omemoManager, OmemoDevice device, T_IdKey t_idKey) {
File identityKeyPath = hierarchy.getContactsIdentityKeyPath(omemoManager, device);
try {
writeBytes(identityKeyPath, keyUtil().identityKeyToBytes(t_idKey));
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write omemoIdentityKey of " + device + ": " + e, e);
}
}
@Override
public boolean isTrustedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint) {
File trustPath = hierarchy.getContactsTrustPath(omemoManager, device);
try {
String depositedFingerprint = new String(readBytes(trustPath), StringUtils.UTF8);
return depositedFingerprint.length() > 2
&& depositedFingerprint.charAt(0) == '1'
&& new OmemoFingerprint(depositedFingerprint.substring(2)).equals(fingerprint);
} catch (IOException e) {
return false;
}
}
@Override
public boolean isDecidedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint) {
File trustPath = hierarchy.getContactsTrustPath(omemoManager, device);
try {
String depositedFingerprint = new String(readBytes(trustPath), StringUtils.UTF8);
return depositedFingerprint.length() > 2
&& (depositedFingerprint.charAt(0) == '1' || depositedFingerprint.charAt(0) == '2')
&& new OmemoFingerprint(depositedFingerprint.substring(2)).equals(fingerprint);
} catch (IOException e) {
return false;
}
}
@Override
public void trustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint) {
File trustPath = hierarchy.getContactsTrustPath(omemoManager, device);
try {
writeBytes(trustPath, ("1 " + fingerprint.toString()).getBytes(StringUtils.UTF8));
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not trust " + device + ": " + e, e);
}
}
@Override
public void distrustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint) {
File trustPath = hierarchy.getContactsTrustPath(omemoManager, device);
try {
writeBytes(trustPath, ("2 " + fingerprint.toString()).getBytes(StringUtils.UTF8));
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not distrust " + device + ": " + e, e);
}
}
@Override
public void setDateOfLastReceivedMessage(OmemoManager omemoManager, OmemoDevice from, Date date) {
File lastMessageReceived = hierarchy.getLastMessageReceivedDatePath(omemoManager, from);
try {
writeLong(lastMessageReceived, date.getTime());
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write date of last received message from " + from + ": " + e, e);
}
}
@Override
public Date getDateOfLastReceivedMessage(OmemoManager omemoManager, OmemoDevice from) {
File lastMessageReceived = hierarchy.getLastMessageReceivedDatePath(omemoManager, from);
try {
long date = readLong(lastMessageReceived);
return date != -1 ? new Date(date) : null;
} catch (IOException e) {
return null;
}
}
@Override
public void setDateOfLastSignedPreKeyRenewal(OmemoManager omemoManager, Date date) {
File lastSignedPreKeyRenewal = hierarchy.getLastSignedPreKeyRenewal(omemoManager);
try {
writeLong(lastSignedPreKeyRenewal, date.getTime());
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write date of last singedPreKey renewal for "
+ omemoManager.getOwnDevice() + ": " + e, e);
}
}
@Override
public Date getDateOfLastSignedPreKeyRenewal(OmemoManager omemoManager) {
File lastSignedPreKeyRenewal = hierarchy.getLastSignedPreKeyRenewal(omemoManager);
try {
long date = readLong(lastSignedPreKeyRenewal);
return date != -1 ? new Date(date) : null;
} catch (IOException e) {
return null;
}
}
@Override
public T_PreKey loadOmemoPreKey(OmemoManager omemoManager, int preKeyId) {
File preKeyPath = hierarchy.getPreKeyPath(omemoManager, preKeyId);
try {
byte[] bytes = readBytes(preKeyPath);
return bytes != null ? keyUtil().preKeyFromBytes(bytes) : null;
} catch (IOException e) {
return null;
}
}
@Override
public void storeOmemoPreKey(OmemoManager omemoManager, int preKeyId, T_PreKey t_preKey) {
File preKeyPath = hierarchy.getPreKeyPath(omemoManager, preKeyId);
try {
writeBytes(preKeyPath, keyUtil().preKeyToBytes(t_preKey));
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write preKey with id " + preKeyId + ": " + e, e);
}
}
@Override
public void removeOmemoPreKey(OmemoManager omemoManager, int preKeyId) {
File preKeyPath = hierarchy.getPreKeyPath(omemoManager, preKeyId);
preKeyPath.delete();
}
@Override
public int loadCurrentSignedPreKeyId(OmemoManager omemoManager) {
File currentSignedPreKeyIdPath = hierarchy.getCurrentSignedPreKeyIdPath(omemoManager);
try {
int i = readInt(currentSignedPreKeyIdPath);
return i == -1 ? 0 : i;
} catch (IOException e) {
return 0;
}
}
@Override
public void storeCurrentSignedPreKeyId(OmemoManager omemoManager, int currentSignedPreKeyId) {
File currentSignedPreKeyIdPath = hierarchy.getCurrentSignedPreKeyIdPath(omemoManager);
try {
writeInt(currentSignedPreKeyIdPath, currentSignedPreKeyId);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write currentSignedPreKeyId "
+ currentSignedPreKeyId + " for " + omemoManager.getOwnDevice() + ": "
+ e, e);
}
}
@Override
public HashMap<Integer, T_PreKey> loadOmemoPreKeys(OmemoManager omemoManager) {
File preKeyDirectory = hierarchy.getPreKeysDirectory(omemoManager);
HashMap<Integer, T_PreKey> preKeys = new HashMap<>();
if (preKeyDirectory == null) {
return preKeys;
}
File[] keys = preKeyDirectory.listFiles();
for (File f : keys != null ? keys : new File[0]) {
try {
byte[] bytes = readBytes(f);
if (bytes == null) {
continue;
}
T_PreKey p = keyUtil().preKeyFromBytes(bytes);
preKeys.put(Integer.parseInt(f.getName()), p);
} catch (IOException e) {
// Do nothing.
}
}
return preKeys;
}
@Override
public T_SigPreKey loadOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId) {
File signedPreKeyPath = new File(hierarchy.getSignedPreKeysDirectory(omemoManager), Integer.toString(signedPreKeyId));
try {
byte[] bytes = readBytes(signedPreKeyPath);
return bytes != null ? keyUtil().signedPreKeyFromBytes(bytes) : null;
} catch (IOException e) {
return null;
}
}
@Override
public HashMap<Integer, T_SigPreKey> loadOmemoSignedPreKeys(OmemoManager omemoManager) {
File signedPreKeysDirectory = hierarchy.getSignedPreKeysDirectory(omemoManager);
HashMap<Integer, T_SigPreKey> signedPreKeys = new HashMap<>();
if (signedPreKeysDirectory == null) {
return signedPreKeys;
}
File[] keys = signedPreKeysDirectory.listFiles();
for (File f : keys != null ? keys : new File[0]) {
try {
byte[] bytes = readBytes(f);
if (bytes == null) {
continue;
}
T_SigPreKey p = keyUtil().signedPreKeyFromBytes(bytes);
signedPreKeys.put(Integer.parseInt(f.getName()), p);
} catch (IOException e) {
// Do nothing.
}
}
return signedPreKeys;
}
@Override
public void storeOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId, T_SigPreKey signedPreKey) {
File signedPreKeyPath = new File(hierarchy.getSignedPreKeysDirectory(omemoManager), Integer.toString(signedPreKeyId));
try {
writeBytes(signedPreKeyPath, keyUtil().signedPreKeyToBytes(signedPreKey));
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write signedPreKey " + signedPreKey
+ " for " + omemoManager.getOwnDevice() + ": " + e, e);
}
}
@Override
public void removeOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId) {
File signedPreKeyPath = new File(hierarchy.getSignedPreKeysDirectory(omemoManager), Integer.toString(signedPreKeyId));
signedPreKeyPath.delete();
}
@Override
public T_Sess loadRawSession(OmemoManager omemoManager, OmemoDevice device) {
File sessionPath = hierarchy.getContactsSessionPath(omemoManager, device);
try {
byte[] bytes = readBytes(sessionPath);
return bytes != null ? keyUtil().rawSessionFromBytes(bytes) : null;
} catch (IOException e) {
return null;
}
}
@Override
public HashMap<Integer, T_Sess> loadAllRawSessionsOf(OmemoManager omemoManager, BareJid contact) {
File contactsDirectory = hierarchy.getContactsDir(omemoManager, contact);
HashMap<Integer, T_Sess> sessions = new HashMap<>();
String[] devices = contactsDirectory.list();
for (String deviceId : devices != null ? devices : new String[0]) {
int id;
try {
id = Integer.parseInt(deviceId);
} catch (NumberFormatException e) {
continue;
}
OmemoDevice device = new OmemoDevice(contact, id);
File session = hierarchy.getContactsSessionPath(omemoManager, device);
try {
byte[] bytes = readBytes(session);
if (bytes == null) {
continue;
}
T_Sess s = keyUtil().rawSessionFromBytes(bytes);
sessions.put(id, s);
} catch (IOException e) {
// Do nothing.
}
}
return sessions;
}
@Override
public void storeRawSession(OmemoManager omemoManager, OmemoDevice device, T_Sess session) {
File sessionPath = hierarchy.getContactsSessionPath(omemoManager, device);
try {
writeBytes(sessionPath, keyUtil().rawSessionToBytes(session));
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write session between our device " + omemoManager.getOwnDevice()
+ " and their device " + device + ": " + e.getMessage());
}
}
@Override
public void removeRawSession(OmemoManager omemoManager, OmemoDevice device) {
File sessionPath = hierarchy.getContactsSessionPath(omemoManager, device);
sessionPath.delete();
}
@Override
public void removeAllRawSessionsOf(OmemoManager omemoManager, BareJid contact) {
File contactsDirectory = hierarchy.getContactsDir(omemoManager, contact);
String[] devices = contactsDirectory.list();
for (String deviceId : devices != null ? devices : new String[0]) {
int id;
try {
id = Integer.parseInt(deviceId);
} catch (NumberFormatException e) {
continue;
}
OmemoDevice device = new OmemoDevice(contact, id);
File session = hierarchy.getContactsSessionPath(omemoManager, device);
session.delete();
}
}
@Override
public boolean containsRawSession(OmemoManager omemoManager, OmemoDevice device) {
File session = hierarchy.getContactsSessionPath(omemoManager, device);
return session.exists();
}
@Override
public CachedDeviceList loadCachedDeviceList(OmemoManager omemoManager, BareJid contact) {
CachedDeviceList cachedDeviceList = new CachedDeviceList();
if (contact == null) {
return null;
}
// active
File activeDevicesPath = hierarchy.getContactsActiveDevicesPath(omemoManager, contact);
try {
cachedDeviceList.getActiveDevices().addAll(readIntegers(activeDevicesPath));
} catch (IOException e) {
// Don't worry...
}
// inactive
File inactiveDevicesPath = hierarchy.getContactsInactiveDevicesPath(omemoManager, contact);
try {
cachedDeviceList.getInactiveDevices().addAll(readIntegers(inactiveDevicesPath));
} catch (IOException e) {
// It's ok :)
}
return cachedDeviceList;
}
@Override
public void storeCachedDeviceList(OmemoManager omemoManager, BareJid contact, CachedDeviceList deviceList) {
if (contact == null) {
return;
}
File activeDevices = hierarchy.getContactsActiveDevicesPath(omemoManager, contact);
try {
writeIntegers(activeDevices, deviceList.getActiveDevices());
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write active devices of deviceList of "
+ contact + ": " + e.getMessage());
}
File inactiveDevices = hierarchy.getContactsInactiveDevicesPath(omemoManager, contact);
try {
writeIntegers(inactiveDevices, deviceList.getInactiveDevices());
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Could not write inactive devices of deviceList of "
+ contact + ": " + e.getMessage());
}
}
@Override
public void purgeOwnDeviceKeys(OmemoManager omemoManager) {
File deviceDirectory = hierarchy.getUserDeviceDirectory(omemoManager);
deleteDirectory(deviceDirectory);
}
private void writeInt(File target, int i) throws IOException {
if (target == null) {
throw new IOException("Could not write integer to null-path.");
}
FileHierarchy.createFile(target);
IOException io = null;
DataOutputStream out = null;
try {
out = new DataOutputStream(new FileOutputStream(target));
out.writeInt(i);
} catch (IOException e) {
io = e;
} finally {
if (out != null) {
out.close();
}
}
if (io != null) {
throw io;
}
}
private int readInt(File target) throws IOException {
if (target == null) {
throw new IOException("Could not read integer from null-path.");
}
IOException io = null;
int i = -1;
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(target));
i = in.readInt();
} catch (IOException e) {
io = e;
} finally {
if (in != null) {
in.close();
}
}
if (io != null) {
throw io;
}
return i;
}
private void writeLong(File target, long i) throws IOException {
if (target == null) {
throw new IOException("Could not write long to null-path.");
}
FileHierarchy.createFile(target);
IOException io = null;
DataOutputStream out = null;
try {
out = new DataOutputStream(new FileOutputStream(target));
out.writeLong(i);
} catch (IOException e) {
io = e;
} finally {
if (out != null) {
out.close();
}
}
if (io != null) {
throw io;
}
}
private long readLong(File target) throws IOException {
if (target == null) {
throw new IOException("Could not read long from null-path.");
}
IOException io = null;
long l = -1;
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(target));
l = in.readLong();
} catch (IOException e) {
io = e;
} finally {
if (in != null) {
in.close();
}
}
if (io != null) {
throw io;
}
return l;
}
private void writeBytes(File target, byte[] bytes) throws IOException {
if (target == null) {
throw new IOException("Could not write bytes to null-path.");
}
// Create file
FileHierarchy.createFile(target);
IOException io = null;
DataOutputStream out = null;
try {
out = new DataOutputStream(new FileOutputStream(target));
out.write(bytes);
} catch (IOException e) {
io = e;
} finally {
if (out != null) {
out.close();
}
}
if (io != null) {
throw io;
}
}
private byte[] readBytes(File target) throws IOException {
if (target == null) {
throw new IOException("Could not read bytes from null-path.");
}
byte[] b = null;
IOException io = null;
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(target));
b = new byte[in.available()];
in.read(b);
} catch (IOException e) {
io = e;
} finally {
if (in != null) {
in.close();
}
}
if (io != null) {
throw io;
}
return b;
}
private void writeIntegers(File target, Set<Integer> integers) throws IOException {
if (target == null) {
throw new IOException("Could not write integers to null-path.");
}
IOException io = null;
DataOutputStream out = null;
try {
out = new DataOutputStream(new FileOutputStream(target));
for (int i : integers) {
out.writeInt(i);
}
} catch (IOException e) {
io = e;
} finally {
if (out != null) {
out.close();
}
}
if (io != null) {
throw io;
}
}
private Set<Integer> readIntegers(File target) throws IOException {
if (target == null) {
throw new IOException("Could not write integers to null-path.");
}
HashSet<Integer> integers = new HashSet<>();
IOException io = null;
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(target));
try {
while (true) {
integers.add(in.readInt());
}
} catch (EOFException e) {
// Reached end of the list.
}
} catch (IOException e) {
io = e;
} finally {
if (in != null) {
in.close();
}
}
if (io != null) {
throw io;
}
return integers;
}
public static void deleteDirectory(File root) {
File[] currList;
Stack<File> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
if (stack.lastElement().isDirectory()) {
currList = stack.lastElement().listFiles();
if (currList != null && currList.length > 0) {
for (File curr : currList) {
stack.push(curr);
}
} else {
stack.pop().delete();
}
} else {
stack.pop().delete();
}
}
}
/**
* This class represents the directory structure of the FileBasedOmemoStoreV2.
* The directory looks as follows:
*
* OMEMO_Store/
* 'romeo@montague.lit'/ //Our bareJid
* ...
* 'juliet@capulet.lit'/ //Our other bareJid
* defaultDeviceId
* '13371234'/ //deviceId
* identityKeyPair //Our identityKeyPair
* lastPreKeyId //Id of the last preKey we generated
* currentSignedPreKeyId //Id of the currently used signedPreKey
* lastSignedPreKeyRenewal //Date of when the signedPreKey was last renewed.
* preKeys/ //Our preKeys
* '1'
* '2'
* ...
* signedPreKeys/ //Our signedPreKeys
* '1'
* '2'
* ...
* contacts/
* 'romeo@capulet.lit'/ //Juliets contact Romeo
* activeDevice //List of Romeos active devices
* inactiveDevices //List of his inactive devices
* 'deviceId'/ //Romeos deviceId
* identityKey //Romeos identityKey
* session //Our session with romeo
* trust //Records about the trust in romeos device
* (lastReceivedMessageDate) //Only, for our own other devices:
* //date of the last received message
*
*/
public static class FileHierarchy {
static final String STORE = "OMEMO_Store";
static final String CONTACTS = "contacts";
static final String DEFAULT_DEVICE_ID = "defaultDeviceId";
static final String IDENTITY_KEY = "identityKey";
static final String IDENTITY_KEY_PAIR = "identityKeyPair";
static final String PRE_KEYS = "preKeys";
static final String LAST_MESSAGE_RECEVIED_DATE = "lastMessageReceivedDate";
static final String LAST_PRE_KEY_ID = "lastPreKeyId";
static final String SIGNED_PRE_KEYS = "signedPreKeys";
static final String CURRENT_SIGNED_PRE_KEY_ID = "currentSignedPreKeyId";
static final String LAST_SIGNED_PRE_KEY_RENEWAL = "lastSignedPreKeyRenewal";
static final String SESSION = "session";
static final String DEVICE_LIST_ACTIVE = "activeDevices";
static final String DEVICE_LIST_INAVTIVE = "inactiveDevices";
static final String TRUST = "trust";
File basePath;
FileHierarchy(File basePath) {
this.basePath = basePath;
basePath.mkdirs();
}
File getStoreDirectory() {
return createDirectory(basePath, STORE);
}
File getUserDirectory(BareJid bareJid) {
return createDirectory(getStoreDirectory(), bareJid.toString());
}
File getUserDeviceDirectory(OmemoManager omemoManager) {
return createDirectory(getUserDirectory(omemoManager.getOwnJid()),
Integer.toString(omemoManager.getDeviceId()));
}
File getContactsDir(OmemoManager omemoManager) {
return createDirectory(getUserDeviceDirectory(omemoManager), CONTACTS);
}
File getContactsDir(OmemoManager omemoManager, BareJid contact) {
return createDirectory(getContactsDir(omemoManager), contact.toString());
}
File getContactsDir(OmemoManager omemoManager, OmemoDevice omemoDevice) {
return createDirectory(getContactsDir(omemoManager, omemoDevice.getJid()),
Integer.toString(omemoDevice.getDeviceId()));
}
File getIdentityKeyPairPath(OmemoManager omemoManager) {
return new File(getUserDeviceDirectory(omemoManager), IDENTITY_KEY_PAIR);
}
File getPreKeysDirectory(OmemoManager omemoManager) {
return createDirectory(getUserDeviceDirectory(omemoManager), PRE_KEYS);
}
File getPreKeyPath(OmemoManager omemoManager, int preKeyId) {
return new File(getPreKeysDirectory(omemoManager), Integer.toString(preKeyId));
}
File getLastMessageReceivedDatePath(OmemoManager omemoManager, OmemoDevice device) {
return new File(getContactsDir(omemoManager, device), LAST_MESSAGE_RECEVIED_DATE);
}
File getLastPreKeyIdPath(OmemoManager omemoManager) {
return new File(getUserDeviceDirectory(omemoManager), LAST_PRE_KEY_ID);
}
File getSignedPreKeysDirectory(OmemoManager omemoManager) {
return createDirectory(getUserDeviceDirectory(omemoManager), SIGNED_PRE_KEYS);
}
File getCurrentSignedPreKeyIdPath(OmemoManager omemoManager) {
return new File(getUserDeviceDirectory(omemoManager), CURRENT_SIGNED_PRE_KEY_ID);
}
File getLastSignedPreKeyRenewal(OmemoManager omemoManager) {
return new File(getUserDeviceDirectory(omemoManager), LAST_SIGNED_PRE_KEY_RENEWAL);
}
File getDefaultDeviceIdPath(BareJid bareJid) {
return new File(getUserDirectory(bareJid), DEFAULT_DEVICE_ID);
}
File getContactsIdentityKeyPath(OmemoManager omemoManager, OmemoDevice omemoDevice) {
return new File(getContactsDir(omemoManager, omemoDevice), IDENTITY_KEY);
}
File getContactsSessionPath(OmemoManager omemoManager, OmemoDevice omemoDevice) {
return new File(getContactsDir(omemoManager, omemoDevice), SESSION);
}
File getContactsActiveDevicesPath(OmemoManager omemoManager, BareJid contact) {
return new File(getContactsDir(omemoManager, contact), DEVICE_LIST_ACTIVE);
}
File getContactsInactiveDevicesPath(OmemoManager omemoManager, BareJid contact) {
return new File(getContactsDir(omemoManager, contact), DEVICE_LIST_INAVTIVE);
}
File getContactsTrustPath(OmemoManager omemoManager, OmemoDevice omemoDevice) {
return new File(getContactsDir(omemoManager, omemoDevice), TRUST);
}
private static File createFile(File f) throws IOException {
File p = f.getParentFile();
createDirectory(p);
f.createNewFile();
return f;
}
private static File createFile(File dir, String filename) throws IOException {
return createFile(new File(dir, filename));
}
private static File createDirectory(File dir, String subdir) {
File f = new File(dir, subdir);
return createDirectory(f);
}
private static File createDirectory(File f) {
if (f.exists() && f.isDirectory()) {
return f;
}
f.mkdirs();
return f;
}
}
}