Installation and usage

The Tanker Client SDK is distributed as the tanker-core gem.

It has been tested on:

  • Linux with Ruby 2.6 and 2.7 and glibc 2.27+.
  • macOS Catalina with Ruby 2.7

To use Tanker in your application:

require 'tanker/core';

config = Tanker::Core::Options.new(app_id: @app.id, writable_path: './tanker_persistent_data')
tanker = Tanker::Core.new(config)

Note

This documentation uses the RBS syntax for type annotation.

Error handling

begin
  tanker.decrypt_utf8(...);
rescue Tanker::Error => e
  if e.code == Tanker::Error::DECRYPTION_FAILED
    raise RuntimeError, 'decryption failed'
  end
end

All errors thrown by Tanker are of the type Tanker::Error which has the following fields:

Field Description
code The error code as an integer, it is one of the constants in Tanker::Error
message Additional details about the error

Here is the list of possible errors:

Error Description
DECRYPTION_FAILED A decryption operation failed
EXPIRED_VERIFICATION The identity verification is expired
GROUP_TOO_BIG The group would exceed the maximum member limit (1000)
INTERNAL_ERROR Tanker internal error, thrown as a last resort
INVALID_ARGUMENT Developer error, one of the function's argument is invalid
INVALID_VERIFICATION An invalid identity verification was provided
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
OPERATION_CANCELED An asynchronous operation was canceled when Tanker stopped
PRECONDITION_FAILED Developer error, a function's precondition was violated
OPERATION_CANCELED An operation was attempted too many times, please try again later
DEVICE_REVOKED The current device is already revoked and cannot be used anymore
CONFLICT There was a conflict with a concurrent operation from another device/user, try again
TOO_MANY_ATTEMPTS There were too many attempts for that action. Please retry later.

Version

This is a static variable containing the SDK version as a string.

version = Tanker::Core::VERSION;

Constructor

config = Tanker::Core::Options.new(app_id: @app.id, writable_path: './tanker_persistent_data')
tanker = Tanker::Core.new(config)
Parameters Description
config: Core::Options The configuration of this Tanker instance, containing:
config.writable_path: String The path where persistent data will be stored
config.app_id: String The app ID

Note

The writablePath should be a writable folder. Tanker will read and store persistent data about the users that will open a session on the current device.

Session management

start

Starts a Tanker session and returns a status.

The Tanker status must be STOPPED.

def start: (String identity) -> Integer # Tanker::Status

The returned value is one of Tanker::Status' constants.

Parameters
identity: String A Tanker identity
Returns
Status::READY The session is ready and fully operational
Status::IDENTITY_REGISTRATION_NEEDED First use of the identity. register_identity() must be called.
Status::IDENTITY_VERIFICATION_NEEDED New device for this identity. verify_identity() must be called.
Throws Description
INVALID_ARGUMENT The provided identity is invalid
PRECONDITION_FAILED The status is not STOPPED
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

stop

Stops the current Tanker session.

def stop: () -> void

status

The status of a Tanker session is available from the status method:

def status: () -> Integer # Tanker::Status

Possible status values are defined as constants in Tanker::Status:

Status Description
STOPPED The session is stopped. start() can be called on it.
READY The session is ready and fully operational
IDENTITY_VERIFICATION_NEEDED The session needs the identity to be verified to become READY
IDENTITY_REGISTRATION_NEEDED This identity is not associated with any verification method. One must be registered.

Identity verification

Verification

Verification is an abstract class. Its children's constructors are:

class EmailVerification
  def initialize: (String email, String verification_code)
end
class OIDCIDTokenVerification
  def initialize: (String oidc_id_token)
end
class PassphraseVerification
  def initialize: (String passphrase)
end
class VerificationKeyVerification
  def initialize: (String verificationKey)
end

All the String arguments must be UTF-8 encoded.

A Verification object is typically used to perform an identity verification, or to register a new identity verification method.

Verification Method

VerificationMethod is an abstract class. Its children are:

class PassphraseVerificationMethod < VerificationMethod; end
class VerificationKeyVerificationMethod < VerificationMethod; end
class OIDCIDTokenVerificationMethod < VerificationMethod; end
class EmailVerificationMethod < VerificationMethod
  attr_reader :email
end

VerificationMethod objects are returned by functions that list verification methods available for an upcoming identity verification, e.g. get_verification_methods() and attach_provisional_identity().

register_identity

Registers the user's identity with which start() has been called, and starts the session.

The Tanker status must be IDENTITY_REGISTRATION_NEEDED.

def register_identity: (Verification verification) -> void
Parameters
verification: Verification The verification to use for identity registration
Throws Description
INVALID_ARGUMENT The verification is ill-formed or incomplete
PRECONDITION_FAILED The status is not IDENTITY_REGISTRATION_NEEDED
EXPIRED_VERIFICATION The verification expired
INVALID_VERIFICATION The verification is invalid
TOO_MANY_ATTEMPTS Too many verification attempts occurred. Please retry later.
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

verify_identity

Verifies the user's identity with which start() has been called, and starts the session.

The Tanker status must be IDENTITY_VERIFICATION_NEEDED.

def verify_identity: (Verification verification) -> void
Parameters
verification: Verification The verification to use
Throws Description
INVALID_ARGUMENT The verification is ill-formed or incomplete
PRECONDITION_FAILED The status is not IDENTITY_VERIFICATION_NEEDED
EXPIRED_VERIFICATION The verification expired
INVALID_VERIFICATION The verification is invalid
TOO_MANY_ATTEMPTS Too many verification attempts occurred. Please retry later.
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore
CONFLICT There was a conflict with a concurrent operation from another device/user, try again

set_verification_method

Adds or overrides a verification method.

The Tanker status must be READY.

def set_verification_method: (Verification verification) -> void
Parameters Description
verification: Verification The verification to use
Throws Description
INVALID_ARGUMENT The verification is ill-formed or incomplete
EXPIRED_VERIFICATION The verification expired
INVALID_VERIFICATION The verification is invalid
PRECONDITION_FAILED The status is not READY
TOO_MANY_ATTEMPTS Too many verification attempts occurred. Please retry later.
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

get_verification_methods

Returns the list of registered verification methods.

The Tanker status must be either IDENTITY_VERIFICATION_NEEDED or READY.

def get_verification_methods: () -> Array[VerificationMethod]
Returns
Array[VerificationMethod] The list of VerificationMethods already set
Throws Description
PRECONDITION_FAILED The status is neither IDENTITY_VERIFICATION_NEEDED nor READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

generate_verification_key

Generates a verification key, registers its public part on Tanker's servers, and returns its private part, which is required to verify the user's identity.

The Tanker status must be IDENTITY_REGISTRATION_NEEDED.

def generate_verification_key: () -> String

Once the verification key has been generated, it is not possible to set up high-level verification methods (e.g. email/passphrase).

The opposite is also true: no high-level verification method must have been set up before calling this function.

It is NOT possible to generate several verification keys.

Warning

This is a low level function for specific use-cases only, as it can have severe security implications. Use it only if high-level identity verification doesn't fit your needs, and you fully understand how it works. Don't hesitate to contact us for help.

Returns
String The generated verification key
Throws Description
PRECONDITION_FAILED The status is not IDENTITY_REGISTRATION_NEEDED
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

Device management

device_id

A property containing the current device's ID.

The Tanker status must be READY.

def device_id: () -> String
Returns
String The current device's ID
Throws Description
PRECONDITION_FAILED The status is not READY

device_list

Retrieves the user's devices list.

The Tanker status must be READY.

def device_list: () -> Array[Device]
Returns
Array[Device] An array of devices

Each Device is an object describing a device, with the following properties:

Fields Description
device_id: String The device ID of the device
revoked: boolean true if the device is already revoked and cannot be used anymore
Throws Description
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

revoke_device

Revokes one of the user's devices.

The Tanker status must be READY.

def revoke_device: (String device_id) -> void
Parameters
device_id: String The device ID of the device to be revoked
Throws Description
INVALID_ARGUMENT The device ID is not one of the users'
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore
CONFLICT There was a conflict with a concurrent operation from another device/user, try again

Encryption

encrypt_utf8

Encrypts an UTF-8 String and returns the result as an ASCII-8BIT String. It will be shared with individual users and groups specified in the EncryptionOptions.

The Tanker status must be READY.

def encrypt_utf8: (String clear_text, ?EncryptionOptions options) -> String
Parameters
clear_text: String The clear text to be encrypted
options: EncryptionOptions Encryption and sharing options (optional)
Returns
String The encrypted data
Throws Description
INVALID_ARGUMENT Some recipients (groups or users) have not been found
INVALID_ARGUMENT The string is not UTF-8 encoded
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

encrypt_data

Encrypts raw bytes passed as an ASCII-8BIT encoded String and returns the resulting encrypted resource as an ASCII-8BIT String too. It will be shared with individual users and groups specified in the EncryptionOptions.

The Tanker status must be READY.

def encrypt_data: (String clear_data, ?EncryptionOptions options) -> String
Parameters
clear_data: String The clear data to encrypt
options: EncryptionOptions Encryption and sharing options (optional)
Returns
String The encrypted data
Throws Description
INVALID_ARGUMENT Some recipients (groups or users) have not been found
INVALID_ARGUMENT The string is not ASCII-8BIT encoded
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

encrypt_stream

Creates an encryption stream wrapping clear_stream.

def encrypt_stream: (IO clear_stream, ?EncryptionOptions encryption_options) -> IO

Warning

After calling this function, clear_stream will be handled and closed by Tanker, it must not be used by your code! Concurrent usage will lead to undefined behavior.

Parameters
clear_stream: IO The stream containing data to encrypt
options: EncryptionOptions Encryption and sharing options (optional)
Returns
IO The encrypted stream
Throws Description
INVALID_ARGUMENT Some recipients (groups or users) have not been found
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

EncryptionOptions

class EncryptionOptions
  def initialize: (
      ?share_with_users: Array<String>,
      ?share_with_groups: Array<String>,
      ?share_with_self: bool,
  )
end

The share_with_users and share_with_groups options allow you to specify who will be able to decrypt the resource. By default the resource will be shared with its creator. To prevent that, set share_with_self to false.

In general, if you need to share a resource with multiple users, it is advised to create groups and use share_with_groups.

Fields Default Description
share_with_users: Array[String] [] User PublicTankerIdentities to share with (the current user's identity will be automatically appended)
share_with_groups: Array[String] [] Group IDs to share with
share_with_self: bool true Should the encrypted data be decryptable by the author

decrypt_utf8

Decrypts a resource passed as an ASCII-8BIT encoded String and returns an UTF-8 encoded String.

def decrypt_utf8: (String encrypted_data) -> String
Parameters
encrypted_data: String The encrypted data to be decrypted
Returns
String The decrypted string
Throws Description
DECRYPTION_FAILED The encrypted data is either corrupted or the current user has no right to decrypt it
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable, and the key is not locally available
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

decrypt_data

Decrypts a resource passed as an ASCII-8BIT encoded String and returns an ASCII-8BIT encoded String.

def decrypt_data: (String encrypted_data) -> String
Parameters
encrypted_data: String The encrypted data to decrypt
Returns
String The decrypted data
Throws Description
DECRYPTION_FAILED The encrypted data is either corrupted or the current user has no right to decrypt it
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable, and the key is not locally available
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

decrypt_stream

Creates a decryption stream wrapping encrypted_stream.

def decrypt_stream: (IO encrypted_stream) -> IO

Warning

After calling this function, encrypted_stream will be handled and closed by Tanker, it must not be used by your code! Concurrent usage will lead to undefined behavior.

Parameters
encrypted_stream: IO The stream containing data to decrypt
Returns
IO The decrypted data stream
Throws Description
DECRYPTION_FAILED The encrypted data is either corrupted or the current user has no right to decrypt it
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable, and the key is not locally available
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

Encryption Sessions

create_encryption_session

Create an encryption session that will allow doing multiple encryption operations with a reduced number of keys.

def create_encryption_session: (?EncryptionOptions options) -> Core::EncryptionSession
Parameters
options: EncryptionOptions Users and/or groups with whom to share the content encrypted in the session
Returns
EncryptionSession A new encryption session
Throws Description
INVALID_ARGUMENT Some recipients (groups or users) have not been found
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

EncryptionSession.encrypt_utf8

Encrypt some text as part of the encryption session.

def encrypt_utf8: (String clear_text) -> String
Parameters
clear_text: string The clear text to be encrypted
Returns
String The encrypted data

EncryptionSession.encrypt_data

Encrypt some data as part of the encryption session.

def encrypt_data: (String clear_data) -> String
Parameters
clear_data: String The clear data to encrypt
Returns
String The encrypted data

EncryptionSession.encrypt_stream

Creates an encryption stream bound to this encryption session wrapping clear_stream.

def encrypt_stream: (IO clear_stream) -> IO

Warning

After calling this function, encrypted_stream will be handled and closed by Tanker, it must not be used by your code! Concurrent usage will lead to undefined behavior.

Parameters
clear_stream: IO The stream containing data to encrypt
Returns
IO The encrypted data stream

EncryptionSession.resource_id

Get the resource ID of this encryption session that can be used to call share(). This will share all the data encrypted within this session.

def resource_id: () -> String
Returns
String The ID of the given encryption session

Groups management

create_group

Creates a group with users' public identities, and returns its ID.

The Tanker status must be READY.

def create_group: (Array[String] public_identities) -> String

Note

The maximum number of users per group is 1000.

Parameters
public_identities: Array[String] Group members' public identities
Returns
String The newly created group's ID
Throws Description
INVALID_ARGUMENT Some recipients (groups or users) have not been found. The whole operation is canceled.
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

update_group_members

Add members to an existing group.

The Tanker status must be READY.

def update_group_members: (String group_id, users_to_add: Array[String]) -> void

The new group members will automatically get access to all resources previously shared with the group.

Parameters
group_id: string Group ID to modify
users_to_add: Array[String] Public identities of users to add to the group
Throws Description
INVALID_ARGUMENT Some recipients (groups or users) have not been found. The whole operation is canceled.
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore
CONFLICT There was a conflict with a concurrent operation from another device/user, try again

Sharing

Sharing a resource can either be done during encryption using the encryption options, or by calling share() afterwards.

get_resource_id

Retrieves an encrypted resource's ID.

def get_resource_id: (String encrypted_data) -> String

The resource ID can then be used to call share().

Note

This function does not have any requirement on Tanker's status.

Parameters
encrypted_data: String The encrypted resource of which you want the ID
Returns
String The ID of the given encrypted resource
Throws Description
INVALID_ARGUMENT The argument is an invalid resource
PRECONDITION_FAILED The status is not READY

share

Shares resources with users and groups.

The Tanker status must be READY.

def share: (Array<String> resource_ids, SharingOptions options) -> void

This function either fully succeeds or fails. In this case, it does not share with any recipient.

Parameters
resource_ids: Array[String] Resource IDs to share
options: SharingOptions Object defining the recipients of the sharing operation
Throws Description
PRECONDITION_FAILED The status is not READY
INVALID_ARGUMENT Some recipients (groups or users) have not been found
INVALID_ARGUMENT Some resource IDs have not been found
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

SharingOptions

class SharingOptions
  def initialize: (share_with_users: Array<String>, share_with_groups: Array<String>)
end

The share_with_users and share_with_groups options allow you to specify who will be able to decrypt the resource.

In general, if you need to share a resource with multiple users, it is advised to create groups and use share_with_groups.

Fields Default Description
share_with_users: Array[String] [] User PublicTankerIdentities to share with (the current user's identity will be automatically appended)
share_with_groups: Array[String] [] Group IDs to share with

Pre-registration sharing

attach_provisional_identity

Attaches a provisional identity to the user.

The Tanker status must be READY.

def attach_provisional_identity: (String provisional_identity) -> Core::AttachResult

Depending on the result, verifying the provisional identity with verify_provisional_identity() might be necessary.

Parameters
provisional_identity: String A provisional identity
Returns
Core::AttachResult An AttachResult
Throws Description
INVALID_ARGUMENT The provided provisional identity is invalid
PRECONDITION_FAILED The status is not READY
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

AttachResult

The attach_provisional_identity() function returns a type with the following properties:

Field Description
status: Integer The provisional identity's status. Either READY or IDENTITY_VERIFICATION_NEEDED
verification_method: VerificationMethod A VerificationMethod containing the email matching the created provisional identity

verify_provisional_identity

Verifies an attached provisional identity.

To be called when the status returned by attach_provisional_identity() is IDENTITY_VERIFICATION_NEEDED.

def verify_provisional_identity: (Verification verification) -> void

Once the provisional identity is verified, every resource shared with it can now be decrypted by the user, who also joins every group in which the provisional identity was a member.

Parameters
verification: Verification A verification containing the provisional identity's email, and the verification code
Throws
INVALID_ARGUMENT The verification is ill-formed or incomplete
PRECONDITION_FAILED The status of the current session is not READY
PRECONDITION_FAILED The status of the attach result is not IDENTITY_VERIFICATION_NEEDED
EXPIRED_VERIFICATION The verification expired
INVALID_VERIFICATION The verification is invalid
TOO_MANY_ATTEMPTS Too many verification attempts occurred. Please retry later.
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
DEVICE_REVOKED The current device is already revoked and cannot be used anymore

Events

Tanker defines a set of functions and callback handlers to handle events. Call connect_#{event_name}_handler() with your callback to subscribe to the event.

You can unsubscribe from the event by calling disconnect_handler with your callback.

deviceRevoked

Emitted when the current device has been revoked and cannot be used anymore. The revocation can be initiated on any device the user has registered, including the current device.

def connect_device_revoked_handler: (&block) -> void

Utilities

prehash_password

Utility function to hash a password client side. It takes an UTF-8 String and returns a ASCII-8BIT String.

def self.prehash_password: (String password) -> String

This function is only useful in the specific case described in the verification by passphrase guide.