use of org.matrix.androidsdk.crypto.data.MXOlmSessionResult in project matrix-android-sdk by matrix-org.
the class CryptoTest method test04_testEnsureOlmSessionsForUsers.
@Test
public void test04_testEnsureOlmSessionsForUsers() throws Exception {
Log.e(LOG_TAG, "test04_testEnsureOlmSessionsForUsers");
Context context = InstrumentationRegistry.getContext();
createAliceAccount();
final HashMap<String, Object> results = new HashMap<>();
mAliceSession.getCredentials().deviceId = "AliceDevice";
final CountDownLatch lock0 = new CountDownLatch(1);
mAliceSession.enableCrypto(true, new ApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
results.put("enableCryptoAlice", "enableCryptoAlice");
lock0.countDown();
}
@Override
public void onNetworkError(Exception e) {
lock0.countDown();
}
@Override
public void onMatrixError(MatrixError e) {
lock0.countDown();
}
@Override
public void onUnexpectedError(Exception e) {
lock0.countDown();
}
});
lock0.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("enableCryptoAlice"));
createBobAccount();
final CountDownLatch lock2 = new CountDownLatch(1);
mBobSession.enableCrypto(true, new ApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
results.put("enableCryptoBob", "enableCryptoAlice");
lock2.countDown();
}
@Override
public void onNetworkError(Exception e) {
lock2.countDown();
}
@Override
public void onMatrixError(MatrixError e) {
lock2.countDown();
}
@Override
public void onUnexpectedError(Exception e) {
lock2.countDown();
}
});
lock2.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("enableCryptoBob"));
final CountDownLatch lock3 = new CountDownLatch(1);
mBobSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(mBobSession.getMyUserId(), mAliceSession.getMyUserId()), false, new ApiCallback<MXUsersDevicesMap<MXDeviceInfo>>() {
@Override
public void onSuccess(MXUsersDevicesMap<MXDeviceInfo> map) {
results.put("downloadKeys", map);
lock3.countDown();
}
@Override
public void onNetworkError(Exception e) {
lock3.countDown();
}
@Override
public void onMatrixError(MatrixError e) {
lock3.countDown();
}
@Override
public void onUnexpectedError(Exception e) {
lock3.countDown();
}
});
lock3.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("downloadKeys"));
final CountDownLatch lock4 = new CountDownLatch(1);
mBobSession.getCrypto().ensureOlmSessionsForUsers(Arrays.asList(mBobSession.getMyUserId(), mAliceSession.getMyUserId()), new ApiCallback<MXUsersDevicesMap<MXOlmSessionResult>>() {
@Override
public void onSuccess(MXUsersDevicesMap<MXOlmSessionResult> info) {
results.put("ensureOlmSessionsForUsers", info);
lock4.countDown();
}
@Override
public void onNetworkError(Exception e) {
lock4.countDown();
}
@Override
public void onMatrixError(MatrixError e) {
lock4.countDown();
}
@Override
public void onUnexpectedError(Exception e) {
lock4.countDown();
}
});
lock4.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("ensureOlmSessionsForUsers"));
MXUsersDevicesMap<MXOlmSessionResult> result = (MXUsersDevicesMap<MXOlmSessionResult>) results.get("ensureOlmSessionsForUsers");
assertTrue(result.getUserIds().size() == 1);
MXOlmSessionResult sessionWithAliceDevice = result.getObject("AliceDevice", mAliceSession.getMyUserId());
assertTrue(null != sessionWithAliceDevice);
assertTrue(null != sessionWithAliceDevice.mSessionId);
assertTrue(TextUtils.equals(sessionWithAliceDevice.mDevice.deviceId, "AliceDevice"));
Credentials bobCredentials = mBobSession.getCredentials();
Uri uri = Uri.parse(CryptoTestHelper.TESTS_HOME_SERVER_URL);
HomeServerConnectionConfig hs = new HomeServerConnectionConfig(uri);
hs.setCredentials(bobCredentials);
IMXStore store = new MXFileStore(hs, context);
MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context);
final CountDownLatch lock5 = new CountDownLatch(1);
MXStoreListener listener = new MXStoreListener() {
@Override
public void postProcess(String accountId) {
}
@Override
public void onStoreReady(String accountId) {
results.put("onStoreReady", "onStoreReady");
lock5.countDown();
}
@Override
public void onStoreCorrupted(String accountId, String description) {
lock5.countDown();
}
@Override
public void onStoreOOM(String accountId, String description) {
lock5.countDown();
}
};
bobSession2.getDataHandler().getStore().addMXStoreListener(listener);
bobSession2.getDataHandler().getStore().open();
bobSession2.getDataHandler().addListener(new MXEventListener() {
@Override
public void onStoreReady() {
lock5.countDown();
}
});
lock5.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("onStoreReady"));
final CountDownLatch lock5b = new CountDownLatch(2);
MXEventListener eventListener = new MXEventListener() {
@Override
public void onInitialSyncComplete(String toToken) {
results.put("onInitialSyncComplete", "onInitialSyncComplete");
lock5b.countDown();
}
@Override
public void onCryptoSyncComplete() {
results.put("onCryptoSyncComplete", "onCryptoSyncComplete");
lock5b.countDown();
}
};
bobSession2.getDataHandler().addListener(eventListener);
bobSession2.startEventStream(null);
lock5b.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("onInitialSyncComplete"));
assertTrue(results.containsKey("onCryptoSyncComplete"));
final CountDownLatch lock6 = new CountDownLatch(1);
bobSession2.getCrypto().ensureOlmSessionsForUsers(Arrays.asList(bobSession2.getMyUserId(), mAliceSession.getMyUserId()), new ApiCallback<MXUsersDevicesMap<MXOlmSessionResult>>() {
@Override
public void onSuccess(MXUsersDevicesMap<MXOlmSessionResult> info) {
results.put("ensureOlmSessionsForUsers2", info);
lock6.countDown();
}
@Override
public void onNetworkError(Exception e) {
lock6.countDown();
}
@Override
public void onMatrixError(MatrixError e) {
lock6.countDown();
}
@Override
public void onUnexpectedError(Exception e) {
lock6.countDown();
}
});
lock6.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("ensureOlmSessionsForUsers2"));
MXUsersDevicesMap<MXOlmSessionResult> result2 = (MXUsersDevicesMap<MXOlmSessionResult>) results.get("ensureOlmSessionsForUsers2");
MXOlmSessionResult sessionWithAliceDevice2 = result2.getObject("AliceDevice", mAliceSession.getMyUserId());
assertTrue(null != sessionWithAliceDevice2);
assertTrue(null != sessionWithAliceDevice2.mSessionId);
assertTrue(TextUtils.equals(sessionWithAliceDevice2.mDevice.deviceId, "AliceDevice"));
mBobSession.clear(context);
mAliceSession.clear(context);
bobSession2.clear(context);
}
use of org.matrix.androidsdk.crypto.data.MXOlmSessionResult in project matrix-android-sdk by matrix-org.
the class MXCrypto method ensureOlmSessionsForDevices.
/**
* Try to make sure we have established olm sessions for the given devices.
* It must be called in getCryptoHandler() thread.
* The callback is called in the UI thread.
*
* @param devicesByUser a map from userid to list of devices.
* @param callback teh asynchronous callback
*/
public void ensureOlmSessionsForDevices(final HashMap<String, ArrayList<MXDeviceInfo>> devicesByUser, final ApiCallback<MXUsersDevicesMap<MXOlmSessionResult>> callback) {
ArrayList<MXDeviceInfo> devicesWithoutSession = new ArrayList<>();
final MXUsersDevicesMap<MXOlmSessionResult> results = new MXUsersDevicesMap<>();
Set<String> userIds = devicesByUser.keySet();
for (String userId : userIds) {
ArrayList<MXDeviceInfo> deviceInfos = devicesByUser.get(userId);
for (MXDeviceInfo deviceInfo : deviceInfos) {
String deviceId = deviceInfo.deviceId;
String key = deviceInfo.identityKey();
String sessionId = mOlmDevice.getSessionId(key);
if (TextUtils.isEmpty(sessionId)) {
devicesWithoutSession.add(deviceInfo);
}
MXOlmSessionResult olmSessionResult = new MXOlmSessionResult(deviceInfo, sessionId);
results.setObject(olmSessionResult, userId, deviceId);
}
}
if (devicesWithoutSession.size() == 0) {
if (null != callback) {
getUIHandler().post(new Runnable() {
@Override
public void run() {
callback.onSuccess(results);
}
});
}
return;
}
// Prepare the request for claiming one-time keys
MXUsersDevicesMap<String> usersDevicesToClaim = new MXUsersDevicesMap<>();
final String oneTimeKeyAlgorithm = MXKey.KEY_SIGNED_CURVE_25519_TYPE;
for (MXDeviceInfo device : devicesWithoutSession) {
usersDevicesToClaim.setObject(oneTimeKeyAlgorithm, device.userId, device.deviceId);
}
// TODO: this has a race condition - if we try to send another message
// while we are claiming a key, we will end up claiming two and setting up
// two sessions.
//
// That should eventually resolve itself, but it's poor form.
Log.d(LOG_TAG, "## claimOneTimeKeysForUsersDevices() : " + usersDevicesToClaim);
mSession.getCryptoRestClient().claimOneTimeKeysForUsersDevices(usersDevicesToClaim, new ApiCallback<MXUsersDevicesMap<MXKey>>() {
@Override
public void onSuccess(final MXUsersDevicesMap<MXKey> oneTimeKeys) {
getEncryptingThreadHandler().post(new Runnable() {
@Override
public void run() {
try {
Log.d(LOG_TAG, "## claimOneTimeKeysForUsersDevices() : keysClaimResponse.oneTimeKeys: " + oneTimeKeys);
Set<String> userIds = devicesByUser.keySet();
for (String userId : userIds) {
ArrayList<MXDeviceInfo> deviceInfos = devicesByUser.get(userId);
for (MXDeviceInfo deviceInfo : deviceInfos) {
MXKey oneTimeKey = null;
List<String> deviceIds = oneTimeKeys.getUserDeviceIds(userId);
if (null != deviceIds) {
for (String deviceId : deviceIds) {
MXOlmSessionResult olmSessionResult = results.getObject(deviceId, userId);
if (null != olmSessionResult.mSessionId) {
// We already have a result for this device
continue;
}
MXKey key = oneTimeKeys.getObject(deviceId, userId);
if (TextUtils.equals(key.type, oneTimeKeyAlgorithm)) {
oneTimeKey = key;
}
if (null == oneTimeKey) {
Log.d(LOG_TAG, "## ensureOlmSessionsForDevices() : No one-time keys " + oneTimeKeyAlgorithm + " for device " + userId + " : " + deviceId);
continue;
}
// Update the result for this device in results
olmSessionResult.mSessionId = verifyKeyAndStartSession(oneTimeKey, userId, deviceInfo);
}
}
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "## ensureOlmSessionsForDevices() " + e.getMessage());
}
if (!hasBeenReleased()) {
if (null != callback) {
getUIHandler().post(new Runnable() {
@Override
public void run() {
callback.onSuccess(results);
}
});
}
}
}
});
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## ensureOlmSessionsForUsers(): claimOneTimeKeysForUsersDevices request failed" + e.getMessage());
if (null != callback) {
callback.onNetworkError(e);
}
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "## ensureOlmSessionsForUsers(): claimOneTimeKeysForUsersDevices request failed" + e.getMessage());
if (null != callback) {
callback.onMatrixError(e);
}
}
@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "## ensureOlmSessionsForUsers(): claimOneTimeKeysForUsersDevices request failed" + e.getMessage());
if (null != callback) {
callback.onUnexpectedError(e);
}
}
});
}
use of org.matrix.androidsdk.crypto.data.MXOlmSessionResult in project matrix-android-sdk by matrix-org.
the class MXMegolmDecryption method shareKeysWithDevice.
@Override
public void shareKeysWithDevice(final IncomingRoomKeyRequest request) {
// sanity checks
if ((null == request) || (null == request.mRequestBody)) {
return;
}
final String userId = request.mUserId;
mSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(userId), false, new ApiCallback<MXUsersDevicesMap<MXDeviceInfo>>() {
@Override
public void onSuccess(MXUsersDevicesMap<MXDeviceInfo> devicesMap) {
final String deviceId = request.mDeviceId;
final MXDeviceInfo deviceInfo = mSession.getCrypto().mCryptoStore.getUserDevice(deviceId, userId);
if (null != deviceInfo) {
final RoomKeyRequestBody body = request.mRequestBody;
HashMap<String, ArrayList<MXDeviceInfo>> devicesByUser = new HashMap<>();
devicesByUser.put(userId, new ArrayList<>(Arrays.asList(deviceInfo)));
mSession.getCrypto().ensureOlmSessionsForDevices(devicesByUser, new ApiCallback<MXUsersDevicesMap<MXOlmSessionResult>>() {
@Override
public void onSuccess(MXUsersDevicesMap<MXOlmSessionResult> map) {
MXOlmSessionResult olmSessionResult = map.getObject(deviceId, userId);
if ((null == olmSessionResult) || (null == olmSessionResult.mSessionId)) {
// so just skip it.
return;
}
Log.d(LOG_TAG, "## shareKeysWithDevice() : sharing keys for session " + body.sender_key + "|" + body.session_id + " with device " + userId + ":" + deviceId);
MXOlmInboundGroupSession2 inboundGroupSession = mSession.getCrypto().getOlmDevice().getInboundGroupSession(body.session_id, body.sender_key, body.room_id);
Map<String, Object> payloadJson = new HashMap<>();
payloadJson.put("type", Event.EVENT_TYPE_FORWARDED_ROOM_KEY);
payloadJson.put("content", inboundGroupSession.exportKeys());
Map<String, Object> encodedPayload = mSession.getCrypto().encryptMessage(payloadJson, Arrays.asList(deviceInfo));
MXUsersDevicesMap<Map<String, Object>> sendToDeviceMap = new MXUsersDevicesMap<>();
sendToDeviceMap.setObject(encodedPayload, userId, deviceId);
Log.d(LOG_TAG, "## shareKeysWithDevice() : sending to " + userId + ":" + deviceId);
mSession.getCryptoRestClient().sendToDevice(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, sendToDeviceMap, new ApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
Log.d(LOG_TAG, "## shareKeysWithDevice() : sent to " + userId + ":" + deviceId);
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : sendToDevice " + userId + ":" + deviceId + " failed " + e.getMessage());
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : sendToDevice " + userId + ":" + deviceId + " failed " + e.getMessage());
}
@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : sendToDevice " + userId + ":" + deviceId + " failed " + e.getMessage());
}
});
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : ensureOlmSessionsForDevices " + userId + ":" + deviceId + " failed " + e.getMessage());
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : ensureOlmSessionsForDevices " + userId + ":" + deviceId + " failed " + e.getMessage());
}
@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : ensureOlmSessionsForDevices " + userId + ":" + deviceId + " failed " + e.getMessage());
}
});
} else {
Log.e(LOG_TAG, "## shareKeysWithDevice() : ensureOlmSessionsForDevices " + userId + ":" + deviceId + " not found");
}
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : downloadKeys " + userId + " failed " + e.getMessage());
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : downloadKeys " + userId + " failed " + e.getMessage());
}
@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "## shareKeysWithDevice() : downloadKeys " + userId + " failed " + e.getMessage());
}
});
}
use of org.matrix.androidsdk.crypto.data.MXOlmSessionResult in project matrix-android-sdk by matrix-org.
the class MXMegolmEncryption method shareUserDevicesKey.
/**
* Share the device keys of a an user
*
* @param session the session info
* @param devicesByUser the devices map
* @param callback the asynchronous callback
*/
private void shareUserDevicesKey(final MXOutboundSessionInfo session, final HashMap<String, ArrayList<MXDeviceInfo>> devicesByUser, final ApiCallback<Void> callback) {
final String sessionKey = mCrypto.getOlmDevice().getSessionKey(session.mSessionId);
final int chainIndex = mCrypto.getOlmDevice().getMessageIndex(session.mSessionId);
HashMap<String, Object> submap = new HashMap<>();
submap.put("algorithm", MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM);
submap.put("room_id", mRoomId);
submap.put("session_id", session.mSessionId);
submap.put("session_key", sessionKey);
submap.put("chain_index", chainIndex);
final HashMap<String, Object> payload = new HashMap<>();
payload.put("type", Event.EVENT_TYPE_ROOM_KEY);
payload.put("content", submap);
final long t0 = System.currentTimeMillis();
Log.d(LOG_TAG, "## shareUserDevicesKey() : starts");
mCrypto.ensureOlmSessionsForDevices(devicesByUser, new ApiCallback<MXUsersDevicesMap<MXOlmSessionResult>>() {
@Override
public void onSuccess(final MXUsersDevicesMap<MXOlmSessionResult> results) {
mCrypto.getEncryptingThreadHandler().post(new Runnable() {
@Override
public void run() {
Log.d(LOG_TAG, "## shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after " + (System.currentTimeMillis() - t0) + " ms");
MXUsersDevicesMap<Map<String, Object>> contentMap = new MXUsersDevicesMap<>();
boolean haveTargets = false;
List<String> userIds = results.getUserIds();
for (String userId : userIds) {
ArrayList<MXDeviceInfo> devicesToShareWith = devicesByUser.get(userId);
for (MXDeviceInfo deviceInfo : devicesToShareWith) {
String deviceID = deviceInfo.deviceId;
MXOlmSessionResult sessionResult = results.getObject(deviceID, userId);
if ((null == sessionResult) || (null == sessionResult.mSessionId)) {
// so just skip it.
continue;
}
Log.d(LOG_TAG, "## shareUserDevicesKey() : Sharing keys with device " + userId + ":" + deviceID);
// noinspection ArraysAsListWithZeroOrOneArgument,ArraysAsListWithZeroOrOneArgument
contentMap.setObject(mCrypto.encryptMessage(payload, Arrays.asList(sessionResult.mDevice)), userId, deviceID);
haveTargets = true;
}
}
if (haveTargets && !mCrypto.hasBeenReleased()) {
final long t0 = System.currentTimeMillis();
Log.d(LOG_TAG, "## shareUserDevicesKey() : has target");
mSession.getCryptoRestClient().sendToDevice(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, contentMap, new ApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
mCrypto.getEncryptingThreadHandler().post(new Runnable() {
@Override
public void run() {
Log.d(LOG_TAG, "## shareUserDevicesKey() : sendToDevice succeeds after " + (System.currentTimeMillis() - t0) + " ms");
// for dead devices on every message.
for (String userId : devicesByUser.keySet()) {
List<MXDeviceInfo> devicesToShareWith = devicesByUser.get(userId);
for (MXDeviceInfo deviceInfo : devicesToShareWith) {
session.mSharedWithDevices.setObject(chainIndex, userId, deviceInfo.deviceId);
}
}
mCrypto.getUIHandler().post(new Runnable() {
@Override
public void run() {
if (null != callback) {
callback.onSuccess(null);
}
}
});
}
});
}
@Override
public void onNetworkError(Exception e) {
Log.d(LOG_TAG, "## shareUserDevicesKey() : sendToDevice onNetworkError " + e.getMessage());
if (null != callback) {
callback.onNetworkError(e);
}
}
@Override
public void onMatrixError(MatrixError e) {
Log.d(LOG_TAG, "## shareUserDevicesKey() : sendToDevice onMatrixError " + e.getMessage());
if (null != callback) {
callback.onMatrixError(e);
}
}
@Override
public void onUnexpectedError(Exception e) {
Log.d(LOG_TAG, "## shareUserDevicesKey() : sendToDevice onUnexpectedError " + e.getMessage());
if (null != callback) {
callback.onUnexpectedError(e);
}
}
});
} else {
Log.d(LOG_TAG, "## shareUserDevicesKey() : no need to sharekey");
if (null != callback) {
mCrypto.getUIHandler().post(new Runnable() {
@Override
public void run() {
callback.onSuccess(null);
}
});
}
}
}
});
}
@Override
public void onNetworkError(Exception e) {
Log.d(LOG_TAG, "## shareUserDevicesKey() : ensureOlmSessionsForDevices failed " + e.getMessage());
if (null != callback) {
callback.onNetworkError(e);
}
}
@Override
public void onMatrixError(MatrixError e) {
Log.d(LOG_TAG, "## shareUserDevicesKey() : ensureOlmSessionsForDevices failed " + e.getMessage());
if (null != callback) {
callback.onMatrixError(e);
}
}
@Override
public void onUnexpectedError(Exception e) {
Log.d(LOG_TAG, "## shareUserDevicesKey() : ensureOlmSessionsForDevices failed " + e.getMessage());
if (null != callback) {
callback.onUnexpectedError(e);
}
}
});
}
Aggregations