Search in sources :

Example 16 with MXDeviceInfo

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);
}
Also used : Context(android.content.Context) MXStoreListener(org.matrix.androidsdk.data.store.MXStoreListener) HashMap(java.util.HashMap) IMXStore(org.matrix.androidsdk.data.store.IMXStore) MXFileStore(org.matrix.androidsdk.data.store.MXFileStore) MXDeviceInfo(org.matrix.androidsdk.crypto.data.MXDeviceInfo) CountDownLatch(java.util.concurrent.CountDownLatch) Uri(android.net.Uri) MXEventListener(org.matrix.androidsdk.listeners.MXEventListener) JsonObject(com.google.gson.JsonObject) MatrixError(org.matrix.androidsdk.rest.model.MatrixError) Credentials(org.matrix.androidsdk.rest.model.login.Credentials) MXCrypto(org.matrix.androidsdk.crypto.MXCrypto) Test(org.junit.Test)

Example 17 with MXDeviceInfo

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();
        }
    });
}
Also used : SimpleApiCallback(org.matrix.androidsdk.rest.callback.SimpleApiCallback) ApiCallback(org.matrix.androidsdk.rest.callback.ApiCallback) MXDeviceInfo(org.matrix.androidsdk.crypto.data.MXDeviceInfo) ArrayList(java.util.ArrayList) List(java.util.List) MatrixError(org.matrix.androidsdk.rest.model.MatrixError) Room(org.matrix.androidsdk.data.Room) SimpleApiCallback(org.matrix.androidsdk.rest.callback.SimpleApiCallback) MXCryptoError(org.matrix.androidsdk.crypto.MXCryptoError)

Example 18 with MXDeviceInfo

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);
            }
        }
    });
}
Also used : MXOlmSessionResult(org.matrix.androidsdk.crypto.data.MXOlmSessionResult) MXDeviceInfo(org.matrix.androidsdk.crypto.data.MXDeviceInfo) ArrayList(java.util.ArrayList) MXUsersDevicesMap(org.matrix.androidsdk.crypto.data.MXUsersDevicesMap) MXKey(org.matrix.androidsdk.crypto.data.MXKey) MatrixError(org.matrix.androidsdk.rest.model.MatrixError)

Example 19 with MXDeviceInfo

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);
}
Also used : HashMap(java.util.HashMap) MXDeviceInfo(org.matrix.androidsdk.crypto.data.MXDeviceInfo) ArrayList(java.util.ArrayList)

Example 20 with MXDeviceInfo

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;
}
Also used : HashMap(java.util.HashMap) MXDeviceInfo(org.matrix.androidsdk.crypto.data.MXDeviceInfo) ArrayList(java.util.ArrayList)

Aggregations

MXDeviceInfo (org.matrix.androidsdk.crypto.data.MXDeviceInfo)25 MatrixError (org.matrix.androidsdk.rest.model.MatrixError)17 HashMap (java.util.HashMap)15 MXUsersDevicesMap (org.matrix.androidsdk.crypto.data.MXUsersDevicesMap)13 ArrayList (java.util.ArrayList)12 CountDownLatch (java.util.concurrent.CountDownLatch)10 JsonObject (com.google.gson.JsonObject)8 Test (org.junit.Test)8 Context (android.content.Context)7 Room (org.matrix.androidsdk.data.Room)6 MXEventListener (org.matrix.androidsdk.listeners.MXEventListener)6 MXCryptoError (org.matrix.androidsdk.crypto.MXCryptoError)4 MXOlmSessionResult (org.matrix.androidsdk.crypto.data.MXOlmSessionResult)4 Uri (android.net.Uri)3 List (java.util.List)3 RoomState (org.matrix.androidsdk.data.RoomState)3 IMXStore (org.matrix.androidsdk.data.store.IMXStore)3 MXFileStore (org.matrix.androidsdk.data.store.MXFileStore)3 MXStoreListener (org.matrix.androidsdk.data.store.MXStoreListener)3 ApiCallback (org.matrix.androidsdk.rest.callback.ApiCallback)3