use of org.matrix.androidsdk.crypto.data.MXDeviceInfo in project matrix-android-sdk by matrix-org.
the class CryptoTest method test02_testCryptoPersistenceInStore.
@Test
public void test02_testCryptoPersistenceInStore() throws Exception {
Log.e(LOG_TAG, "test02_testCryptoPersistenceInStore");
Context context = InstrumentationRegistry.getContext();
final HashMap<String, Object> results = new HashMap<>();
createBobAccount();
mBobSession.getCredentials().deviceId = "BobDevice";
assertTrue(null == mBobSession.getCrypto());
final CountDownLatch lock0 = new CountDownLatch(1);
mBobSession.enableCrypto(true, new ApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
results.put("enableCrypto", "enableCrypto");
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("enableCrypto"));
assertTrue(null != mBobSession.getCrypto());
SystemClock.sleep(1000);
final String deviceCurve25519Key = mBobSession.getCrypto().getOlmDevice().getDeviceCurve25519Key();
final String deviceEd25519Key = mBobSession.getCrypto().getOlmDevice().getDeviceEd25519Key();
final List<MXDeviceInfo> myUserDevices = mBobSession.getCrypto().getUserDevices(mBobSession.getMyUserId());
assertTrue(null != myUserDevices);
assertTrue(1 == myUserDevices.size());
final 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 lock1 = new CountDownLatch(1);
MXStoreListener listener = new MXStoreListener() {
@Override
public void postProcess(String accountId) {
}
@Override
public void onStoreReady(String accountId) {
results.put("onStoreReady", "onStoreReady");
lock1.countDown();
}
@Override
public void onStoreCorrupted(String accountId, String description) {
lock1.countDown();
}
@Override
public void onStoreOOM(String accountId, String description) {
lock1.countDown();
}
};
bobSession2.getDataHandler().getStore().addMXStoreListener(listener);
bobSession2.getDataHandler().getStore().open();
lock1.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("onStoreReady"));
assertTrue(bobSession2.isCryptoEnabled());
final CountDownLatch lock2 = new CountDownLatch(2);
MXEventListener eventsListener = new MXEventListener() {
@Override
public void onInitialSyncComplete(String toToken) {
results.put("onInitialSyncComplete", "onInitialSyncComplete");
lock2.countDown();
}
@Override
public void onCryptoSyncComplete() {
results.put("onCryptoSyncComplete", "onCryptoSyncComplete");
lock2.countDown();
}
};
bobSession2.getDataHandler().addListener(eventsListener);
bobSession2.startEventStream(null);
lock2.await(1000, TimeUnit.MILLISECONDS);
assertTrue(results.containsKey("onInitialSyncComplete"));
assertTrue(results.containsKey("onCryptoSyncComplete"));
MXCrypto crypto = bobSession2.getCrypto();
assertNotNull(crypto);
assertTrue(TextUtils.equals(deviceCurve25519Key, crypto.getOlmDevice().getDeviceCurve25519Key()));
assertTrue(TextUtils.equals(deviceEd25519Key, crypto.getOlmDevice().getDeviceEd25519Key()));
List<MXDeviceInfo> myUserDevices2 = bobSession2.getCrypto().getUserDevices(bobSession2.getMyUserId());
assertTrue(1 == myUserDevices2.size());
assertTrue(TextUtils.equals(myUserDevices2.get(0).deviceId, myUserDevices.get(0).deviceId));
mBobSession.clear(context);
bobSession2.clear(context);
}
use of org.matrix.androidsdk.crypto.data.MXDeviceInfo in project matrix-android-sdk by matrix-org.
the class MXCallsManager method checkPendingIncomingCalls.
/**
* check if there is a pending incoming call
*/
public void checkPendingIncomingCalls() {
// Log.d(LOG_TAG, "checkPendingIncomingCalls");
mUIThreadHandler.post(new Runnable() {
@Override
public void run() {
if (mxPendingIncomingCallId.size() > 0) {
for (String callId : mxPendingIncomingCallId) {
final IMXCall call = getCallWithCallId(callId);
if (null != call) {
final Room room = call.getRoom();
// If there are some unknown devices, the answer event would not be encrypted.
if ((null != room) && room.isEncrypted() && mSession.getCrypto().warnOnUnknownDevices() && (room.getJoinedMembers().size() == 2)) {
// test if the encrypted events are sent only to the verified devices (any room)
mSession.getCrypto().getGlobalBlacklistUnverifiedDevices(new SimpleApiCallback<Boolean>() {
@Override
public void onSuccess(Boolean sendToVerifiedDevicesOnly) {
if (sendToVerifiedDevicesOnly) {
dispatchOnIncomingCall(call, null);
} else {
// test if the encrypted events are sent only to the verified devices (only this room)
mSession.getCrypto().isRoomBlacklistUnverifiedDevices(room.getRoomId(), new SimpleApiCallback<Boolean>() {
@Override
public void onSuccess(Boolean sendToVerifiedDevicesOnly) {
if (sendToVerifiedDevicesOnly) {
dispatchOnIncomingCall(call, null);
} else {
List<RoomMember> members = new ArrayList<>(room.getJoinedMembers());
String userId1 = members.get(0).getUserId();
String userId2 = members.get(1).getUserId();
Log.d(LOG_TAG, "## checkPendingIncomingCalls() : check the unknown devices");
//
mSession.getCrypto().checkUnknownDevices(Arrays.asList(userId1, userId2), new ApiCallback<Void>() {
@Override
public void onSuccess(Void anything) {
Log.d(LOG_TAG, "## checkPendingIncomingCalls() : no unknown device");
dispatchOnIncomingCall(call, null);
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## checkPendingIncomingCalls() : checkUnknownDevices failed " + e.getMessage());
dispatchOnIncomingCall(call, null);
}
@Override
public void onMatrixError(MatrixError e) {
MXUsersDevicesMap<MXDeviceInfo> unknownDevices = null;
if (e instanceof MXCryptoError) {
MXCryptoError cryptoError = (MXCryptoError) e;
if (MXCryptoError.UNKNOWN_DEVICES_CODE.equals(cryptoError.errcode)) {
unknownDevices = (MXUsersDevicesMap<MXDeviceInfo>) cryptoError.mExceptionData;
}
}
if (null != unknownDevices) {
Log.d(LOG_TAG, "## checkPendingIncomingCalls() : checkUnknownDevices found some unknown devices");
} else {
Log.e(LOG_TAG, "## checkPendingIncomingCalls() : checkUnknownDevices failed " + e.getMessage());
}
dispatchOnIncomingCall(call, unknownDevices);
}
@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "## checkPendingIncomingCalls() : checkUnknownDevices failed " + e.getMessage());
dispatchOnIncomingCall(call, null);
}
});
}
}
});
}
}
});
} else {
dispatchOnIncomingCall(call, null);
}
}
}
}
mxPendingIncomingCallId.clear();
}
});
}
use of org.matrix.androidsdk.crypto.data.MXDeviceInfo 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.MXDeviceInfo in project matrix-android-sdk by matrix-org.
the class MXCrypto method ensureOlmSessionsForUsers.
/**
* Try to make sure we have established olm sessions for the given users.
* It must be called in getEncryptingThreadHandler() thread.
* The callback is called in the UI thread.
*
* @param users a list of user ids.
* @param callback the asynchronous callback
*/
public void ensureOlmSessionsForUsers(List<String> users, final ApiCallback<MXUsersDevicesMap<MXOlmSessionResult>> callback) {
Log.d(LOG_TAG, "## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers " + users);
HashMap<String, ArrayList<MXDeviceInfo>> /* userId */
devicesByUser = new HashMap<>();
for (String userId : users) {
devicesByUser.put(userId, new ArrayList<MXDeviceInfo>());
List<MXDeviceInfo> devices = getUserDevices(userId);
for (MXDeviceInfo device : devices) {
String key = device.identityKey();
if (TextUtils.equals(key, mOlmDevice.getDeviceCurve25519Key())) {
// Don't bother setting up session to ourself
continue;
}
if (device.isVerified()) {
// Don't bother setting up sessions with blocked users
continue;
}
devicesByUser.get(userId).add(device);
}
}
ensureOlmSessionsForDevices(devicesByUser, callback);
}
use of org.matrix.androidsdk.crypto.data.MXDeviceInfo in project matrix-android-sdk by matrix-org.
the class MXCrypto method encryptMessage.
/**
* Encrypt an event payload for a list of devices.
* This method must be called from the getCryptoHandler() thread.
*
* @param payloadFields fields to include in the encrypted payload.
* @param deviceInfos list of device infos to encrypt for.
* @return the content for an m.room.encrypted event.
*/
public Map<String, Object> encryptMessage(Map<String, Object> payloadFields, List<MXDeviceInfo> deviceInfos) {
if (hasBeenReleased()) {
return new HashMap<>();
}
HashMap<String, MXDeviceInfo> deviceInfoParticipantKey = new HashMap<>();
ArrayList<String> participantKeys = new ArrayList<>();
for (MXDeviceInfo di : deviceInfos) {
participantKeys.add(di.identityKey());
deviceInfoParticipantKey.put(di.identityKey(), di);
}
HashMap<String, Object> payloadJson = new HashMap<>(payloadFields);
payloadJson.put("sender", mSession.getMyUserId());
payloadJson.put("sender_device", mSession.getCredentials().deviceId);
// Include the Ed25519 key so that the recipient knows what
// device this message came from.
// We don't need to include the curve25519 key since the
// recipient will already know this from the olm headers.
// When combined with the device keys retrieved from the
// homeserver signed by the ed25519 key this proves that
// the curve25519 key and the ed25519 key are owned by
// the same device.
HashMap<String, String> keysMap = new HashMap<>();
keysMap.put("ed25519", mOlmDevice.getDeviceEd25519Key());
payloadJson.put("keys", keysMap);
HashMap<String, Object> ciphertext = new HashMap<>();
for (String deviceKey : participantKeys) {
String sessionId = mOlmDevice.getSessionId(deviceKey);
if (!TextUtils.isEmpty(sessionId)) {
Log.d(LOG_TAG, "Using sessionid " + sessionId + " for device " + deviceKey);
MXDeviceInfo deviceInfo = deviceInfoParticipantKey.get(deviceKey);
payloadJson.put("recipient", deviceInfo.userId);
HashMap<String, String> recipientsKeysMap = new HashMap<>();
recipientsKeysMap.put("ed25519", deviceInfo.fingerprint());
payloadJson.put("recipient_keys", recipientsKeysMap);
String payloadString = JsonUtils.convertToUTF8(JsonUtils.canonicalize(JsonUtils.getGson(false).toJsonTree(payloadJson)).toString());
ciphertext.put(deviceKey, mOlmDevice.encryptMessage(deviceKey, sessionId, payloadString));
}
}
HashMap<String, Object> res = new HashMap<>();
res.put("algorithm", MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM);
res.put("sender_key", mOlmDevice.getDeviceCurve25519Key());
res.put("ciphertext", ciphertext);
return res;
}
Aggregations