powered by Jive Software

Smack 4.4.0: Regenerate OMEMO Identity Implementation

aTalk is trying to implement user option to “Regenerate OMEMO Identity”, after few days of trial and error, finally it settles down on the following code implementation as attached below.
Appreciate if someone would review and advice if the code needs improvement.

The test observations using the code are as follow:
1, The new omemo identity has successfully published to the ejabberd server; and the user/buddy are able to perform omemo message chat using the newly created omemoDevice.
2, However checking on the ejabberd server database, both the publish_item & publish_node tables still contain all the old omemo devices info.

In going through the source, I see that OmemoManager#purgeDeviceList() publishes only the newly create omemoDevice, but no attempt is made to purge the old omemDevices info on server that were previously published.

In this the correct/intended implementation for omemo? Should not the old omemo device info be purged from the server, leaving only the newly created omemDevice info.

  1. Who is responsible to clean up the obsoleted omemo info on server.

  2. Is there a public method in omemoService that can be called to remove the old omemo devices info on the server.

    /**
     * Regenerate new omemo identity for the device
     * 1. Wipeout account Omemo info in database
     * 2. generate fresh user identityKeyPairs, bundle
     * 3. publish it to the server.
     */
    public void regenerate(AccountID accountId)
    {
        ProtocolProviderService pps = accountId.getProtocolProvider();
        if (pps != null) {
            XMPPTCPConnection connection = pps.getConnection();
            if ((connection != null) && connection.isAuthenticated()) {
                // Purge all omemo devices info in database for the specific account
                mDB.purgeOmemoDb(accountId.getAccountJid());
                trustCache.evictAll();

                // Generate new omemoDevice
                BareJid userJid = accountId.getBareJid();
                int defaultDeviceId = OmemoManager.randomDeviceId();
                setDefaultDeviceId(userJid, defaultDeviceId);

                mOmemoManager = OmemoManager.getInstanceFor(connection, defaultDeviceId);
                try {
                    mOmemoManager.setTrustCallback(aTalkTrustCallback);
                    // Publish a new device list with just our own deviceId in it.
                    mOmemoManager.purgeDeviceList();
                } catch (Exception e) {
                    Timber.w("Ignoring setTrustCallBack Exception: %s", e.getMessage());
                }
                // Init and publish to server
                mOmemoManager.initializeAsync(this);
            }
        }
    }

    @Override
    public void initializationFinished(OmemoManager manager)
    {
        Timber.i("Initialize OmemoManager successful for %s", manager.getOwnDevice());
    }

    @Override
    public void initializationFailed(Exception cause)
    {
        String title = aTalkApp.getResString(R.string.omemo_init_failed_title);
        String errMsg = cause.getMessage();
        if (errMsg != null) {
            if (errMsg.contains("CorruptedOmemoKeyException")) {
                String msg = aTalkApp.getResString(R.string.omemo_init_failed_CorruptedOmemoKeyException,
                        mOmemoManager.getOwnDevice(), cause.getMessage());
                DialogActivity.showDialog(aTalkApp.getGlobalContext(), title, msg);
            }
            else {
                aTalkApp.showToastMessage(R.string.omemo_init_failed_noresponse, mOmemoManager.getOwnDevice());
            }
        }
    }

    public void purgeOmemoDb(String account)
    {
        Timber.d(">>> Wiping OMEMO database for account : %s", account);
        SQLiteDatabase db = this.getWritableDatabase();
        String[] deleteArgs = {account};

        db.delete(SQLiteOmemoStore.OMEMO_DEVICES_TABLE_NAME, SQLiteOmemoStore.OMEMO_JID + "=?", deleteArgs);
        db.delete(SQLiteOmemoStore.PREKEY_TABLE_NAME, SQLiteOmemoStore.BARE_JID + "=?", deleteArgs);
        db.delete(SQLiteOmemoStore.SIGNED_PREKEY_TABLE_NAME, SQLiteOmemoStore.BARE_JID + "=?", deleteArgs);
        db.delete(SQLiteOmemoStore.IDENTITIES_TABLE_NAME, SQLiteOmemoStore.BARE_JID + "=?", deleteArgs);
        db.delete(SQLiteOmemoStore.SESSION_TABLE_NAME, SQLiteOmemoStore.BARE_JID + "=?", deleteArgs);
    }