Migrating from version 1.10 to version 2.0

Important caveat

When upgrading to the 2.0 SDK, make sure to upgrade both web and mobile applications at the same time.

Otherwise, you may have blocks pushed to the Tanker servers from the web application that mobile applications won't be able to process.

Server-side changes

The first step is to replace the usertoken SDK with the identity SDK.

Then, if you had existing users with user tokens stored in database, you should convert them to secret identities using the function named upgradeUserToken from the identity SDK.

For instance, in Go:


import (
    "github.com/TankerHQ/identity-go/identity"
)

// Note: error handling omitted for brievity
func GetTankerIdentity(userID string) {
    user := storage.GetUser(userID)

    config := identity.Config {
        AppID: ...,
        AppSecret: ...,
    }

    if user.tankerIdentity != "" {
        // Tanker identity already created, return it
        return user.tankerIdentity
    }

    if user.tankerUserToken != "" {
        // user had a user token, convert to an identity
        user.tankerIdentity = identity.UpradeUserToken(config, userID, user.tankerUserToken)
    }

    if user.tankerIdentity != "" {
        // user had neither user token nor identiny, create a new one, save it and
        // return it
        user.tankerIdentity = identity.Create(config, userID)
    }

    storage.SaveUser(user)
    return user.tankerIdentity
}

Once this is done, you may proceed to adapt server code to store and retrieve identities, and, in case you need it, implement pre-registration sharing

In particular, this means you should modify your authentication routes to send back tanker identities instead of user tokens.

Client-side changes

Overview of method changes

The old and new API methods do not map 1-to-1, since internal behaviors have been redispatched significantly.

Here is a quick recap table to have a grasp of the changes described in the sections hereafter:

SDK 2.0 methods Roughly equivalent to SDK 1.10 methods
start first half of open
registerIdentity second half of open + registerUnlock with a verified method
verifyIdentity second half of open + unlockCurrentDevice
setVerificationMethod additional registerUnlock call, with a verified method
stop close

Starting a session

// Before 2.0
tanker.open(userId, userToken);

// After 2.0
tanker.start(identity);

Note: The future returned by tanker.open() used to resolve when the device was unlocked, using the callback given to tanker.connectUnlockRequiredHandler. Now, the future returned by tanker.start() gets resolved even if the Tanker session is not ready. See the section starting a Tanker session for details.

Use new Tanker status values

// Before 2.0
enum TankerStatus {
  IDLE,
  OPEN,
  USER_CREATION,
  DEVICE_CREATION,
  CLOSING,
}

// After 2.0
enum Status {
  STOPPED,
  READY,
  IDENTITY_REGISTRATION_NEEDED,
  IDENTITY_VERIFICATION_NEEDED
}

Note that you must register a verification method and verify it right away when a user first connects to Tanker. Previously it was possible to create a user without any unlock mechanism in place and thus risk data loss.

Replace registerUnlock with registerIdentity

With email

// Before 2.0
// After open()
TankerUnlockOptions options = new TankerUnlockOptions();
options.setEmail(email);
tanker.registerUnlock(options);

// After 2.0
// After start(), in case status is IDENTITY_REGISTRATION_NEEDED
Verification verification = new EmailVerification(email, verificationCode);
tanker.registerIdentity(verification);

Note

You need to send an email containing the verification code before using other Tanker methods.

With password

Replace password with passphrase:

// Before 2.0
// After open()
TankerUnlockOptions options = new TankerUnlockOptions();
options.setPassword(password);
tanker.registerUnlock(options);

// After 2.0
// After start(), in case status in IDENTITY_REGISTRATION_NEEDED
Verification verification = new PassphraseVerification(passphrase);
tanker.registerIdentity(verification);

Replace unlockCurrentDevice with verifyIdentity

With email

// Before 2.0
// After open()
tanker.unlockCurrentDeviceWithVerificationCode(verificationCode);

// After 2.0
// After start(), in case status is IDENTITY_REGISTRATION_NEEDED
Verification verification = new EmailVerification(email, verificationCode);
tanker.verifyIdentity(verification);

With password

// Before 2.0
// After open()
tanker.unlockCurrentDeviceWithPassword(password);

// After 2.0
// After start(), in case status in IDENTITY_REGISTRATION_NEEDED
Verification verification = new PassphraseVerification(passphrase);
tanker.verifyIdentity(verification);

Replace generateAndRegisterUnlockKey with generateVerificationKey

// Before 2.0
// After open()
String unlockKey = tanker.generateAndRegisterUnlockKey().get();
// In the unlockRequired callback
tanker.unlockCurrentDeviceWithUnlockKey(unlockKey);

// After 2.0
// After start(), in case status is IDENTITY_REGISTRATION_NEEDED
String verificationKey = tanker.generateVerificationKey().get();
// After start(), in case status is IDENTITY_VERIFICATION_NEEDED
Verification verification = new VerificationKeyVerification(verificationKey);
tanker.verifyIdentity(verification);

Replace close with stop

// Before 2.0
tanker.close();

// After 2.0
tanker.stop();

Replace registeredUnlockMethods et al with getVerificationMethods

// Before 2.0
List<TankerUnlockMethodInfo> methods = tanker.registeredUnlockMethods();
boolean hasEmail = tanker.hasRegisteredUnlockMethod(TankerUnlockMethod.EMAIL);
boolean hasAnyMethod = tanker.hasRegisteredUnlockMethods();

// After 2.0
List<VerificationMethod> methods = tanker.getVerificationMethods().get();
boolean hasEmail = false;
for (VerificationMethod method : methods) {
  if (method instanceof EmailVerificationMethod) {
    hasEmail = true;
  }
}
boolean hasAnyMethod; // always true, by design

Replace second call to registerUnlock with setVerificationMethod

By passphrase

// Before 2.0
TankerUnlockOptions options = new TankerUnlockOptions();
options.setPassword(newPassword);
tanker.registerUnlock(options);

// After 2.0
Verification verification = new PassphraseVerification(newPassphrase);
tanker.setVerificationMethod(verification);

By email

// Before 2.0
TankerUnlockOptions options = new TankerUnlockOptions();
options.setEmail(newEmail);
tanker.registerUnlock(options);

// After 2.0
Verification verification = new EmailVerification(newEmail, verificationCode);
tanker.setVerificationMethod(verification);

Replace user IDs with identities

// Before 2.0
TankerEncryptOptions options = new TankerEncryptOptions();
options.shareWithUsers(new String[]{bobId, charlieId});
tanker.encrypt(data, options);

TankerShareOptions options = new TankerShareOptions();
options.shareWithUsers(new String[]{bobId, charlieId});
tanker.share(new String[]{resourceId}, options);

tanker.createGroup(new String[]{bobId, charlieId});
tanker.updateGroupMembers(groupId, new String[]{bobId, charlieId});

// After 2.0
EncryptOptions options = new EncryptOptions();
options.shareWithUsers(new String[]{bobPublicIdentity, charliePublicIdentity});
tanker.encrypt(data, options);

ShareOptions options = new ShareOptions();
options.shareWithUsers(new String[]{bobPublicIdentity, charliePublicIdentity});
tanker.share(new String[]{resourceId}, options);

tanker.createGroup(new String[]{bobPublicIdentity, charliePublicIdentity});
tanker.updateGroupMembers(groupId, new String[]{bobPublicIdentity, charliePublicIdentity});