class Tanker::Core

Main entry point for the Tanker SDK. Can open a Tanker session.

Constants

VERSION

Public Class Methods

native_version() click to toggle source
# File lib/tanker/core/version.rb, line 7
def self.native_version
  CTanker.tanker_version_string
end
new(options) click to toggle source
# File lib/tanker/core/init.rb, line 27
def initialize(options)
  # tanker_init is not called globally to avoid potential logs at global scope
  # some frameworks like to pre-execute statements at global scope and then fork, this fork can
  # interact badly with the threads used in the log handler, so never call Tanker at global scope
  CTanker.tanker_init

  # Do not spam the console of our users.
  self.class.set_log_handler { |_| } unless self.class.test_and_set_log_handler == 1 # rubocop:disable Lint/EmptyBlock

  @revoke_event_handlers = Set.new
  @ctanker = CTanker.tanker_create(options).get
  @freed = false
  ctanker_addr = @ctanker.address
  ObjectSpace.define_finalizer(@ctanker) do |_|
    next if @freed

    CTanker.tanker_destroy(FFI::Pointer.new(:void, ctanker_addr)).get
  end

  @device_revoked_handler = lambda { |_|
    Thread.new { @revoke_event_handlers.each(&:call) }
  }
  CTanker.tanker_event_connect(@ctanker, CTanker::CTankerEvent::DEVICE_REVOKED, @device_revoked_handler, nil).get
end
prehash_password(str) click to toggle source
# File lib/tanker/core/encryption.rb, line 75
def self.prehash_password(str)
  ASSERT_UTF8.call(str)

  CTanker.tanker_prehash_password(str).get_string
end
set_log_handler(&block) click to toggle source
# File lib/tanker/core/init.rb, line 19
def self.set_log_handler(&block) # rubocop:disable Naming/AccessorMethodName
  @log_handler_set = 1
  @log_handler = lambda do |clog|
    block.call LogRecord.new clog[:category], clog[:level], clog[:file], clog[:line], clog[:message]
  end
  CTanker.tanker_set_log_handler @log_handler
end
test_and_set_log_handler() click to toggle source
# File lib/tanker/core/init.rb, line 11
def self.test_and_set_log_handler
  @log_handler_lock.synchronize do
    is_set = @log_handler_set
    @log_handler_set = 1
    return is_set
  end
end

Public Instance Methods

attach_provisional_identity(provisional_identity) click to toggle source
# File lib/tanker/core/session.rb, line 77
def attach_provisional_identity(provisional_identity)
  attach_ptr = CTanker.tanker_attach_provisional_identity(@ctanker, provisional_identity).get
  attach_status = attach_ptr.get(:uint8, 1)
  method_ptr = attach_ptr.get_pointer(FFI::Pointer.size)
  method = (CTanker::CVerificationMethod.new(method_ptr).to_verification_method if method_ptr.address != 0)
  AttachResult.new attach_status, method
end
connect_device_revoked_handler(&block) click to toggle source
# File lib/tanker/core/init.rb, line 64
def connect_device_revoked_handler(&block)
  @revoke_event_handlers.add block
end
create_encryption_session(encryption_options = nil) click to toggle source
# File lib/tanker/core/encryption.rb, line 66
def create_encryption_session(encryption_options = nil)
  unless !encryption_options || encryption_options.is_a?(EncryptionOptions)
    raise TypeError, "expected encryption_options to be a EncryptionOptions, but got a #{encryption_options.class}"
  end

  csession = CTanker.tanker_encryption_session_open(@ctanker, encryption_options).get
  EncryptionSession.new(csession)
end
create_group(member_identities) click to toggle source
# File lib/tanker/core/group.rb, line 7
def create_group(member_identities)
  cmember_identities = CTanker.new_cstring_array member_identities
  CTanker.tanker_create_group(@ctanker, cmember_identities, member_identities.length).get_string
end
decrypt_data(data) click to toggle source
# File lib/tanker/core/encryption.rb, line 25
def decrypt_data(data)
  inbuf = FFI::MemoryPointer.from_string(data)

  decrypted_size = CTanker.tanker_decrypted_size(inbuf, data.bytesize).get.address
  outbuf = FFI::MemoryPointer.new(:char, decrypted_size)

  CTanker.tanker_decrypt(@ctanker, outbuf, inbuf, data.bytesize).get

  outbuf.read_string decrypted_size
end
decrypt_stream(stream) click to toggle source
# File lib/tanker/core/stream.rb, line 35
def decrypt_stream(stream)
  Stream.do_stream_action(stream) { |cb| CTanker.tanker_stream_decrypt(@ctanker, cb, nil) }
end
decrypt_utf8(data) click to toggle source
# File lib/tanker/core/encryption.rb, line 36
def decrypt_utf8(data)
  decrypted = decrypt_data data
  decrypted.force_encoding(Encoding::UTF_8)
end
device_id() click to toggle source
# File lib/tanker/core/session.rb, line 46
def device_id
  CTanker.tanker_device_id(@ctanker).get_string
end
device_list() click to toggle source
# File lib/tanker/core/session.rb, line 50
def device_list
  device_list_ptr = CTanker.tanker_get_device_list(@ctanker).get
  count = device_list_ptr.get(:uint32, FFI::Pointer.size)

  method_base_addr = device_list_ptr.read_pointer
  device_info_list = count.times.map do |i|
    method_ptr = method_base_addr + i * CTanker::CDeviceInfo.size
    CTanker::CDeviceInfo.new(method_ptr)
  end
  CTanker.tanker_free_device_list device_list_ptr
  device_info_list
end
disconnect_handler(&block) click to toggle source
# File lib/tanker/core/init.rb, line 70
def disconnect_handler(&block)
  @revoke_event_handlers.delete block
end
encrypt_data(data, encryption_options = nil) click to toggle source
# File lib/tanker/core/encryption.rb, line 8
def encrypt_data(data, encryption_options = nil)
  unless data.is_a?(String)
    raise TypeError, "expected data to be an ASCII-8BIT binary String, but got a #{data.class}"
  end
  unless data.encoding == Encoding::ASCII_8BIT
    raise ArgumentError, "expected data to be an ASCII-8BIT binary String, but it was #{data.encoding} encoded"
  end

  encrypt_common data, encryption_options
end
encrypt_stream(stream, encryption_options = nil) click to toggle source
# File lib/tanker/core/stream.rb, line 31
def encrypt_stream(stream, encryption_options = nil)
  Stream.do_stream_action(stream) { |cb| CTanker.tanker_stream_encrypt(@ctanker, cb, nil, encryption_options) }
end
encrypt_utf8(str, encryption_options = nil) click to toggle source
# File lib/tanker/core/encryption.rb, line 19
def encrypt_utf8(str, encryption_options = nil)
  ASSERT_UTF8.call(str)

  encrypt_common str, encryption_options
end
free() click to toggle source
# File lib/tanker/core/init.rb, line 52
def free
  @freed = true
  CTanker.tanker_destroy(@ctanker).get
  @ctanker = nil

  public_methods(false).each do |method|
    send(:define_singleton_method, method) do |*_|
      raise "using Tanker::Core##{method} after free"
    end
  end
end
generate_verification_key() click to toggle source
# File lib/tanker/core/session.rb, line 14
def generate_verification_key
  CTanker.tanker_generate_verification_key(@ctanker).get_string
end
get_resource_id(data) click to toggle source
# File lib/tanker/core/encryption.rb, line 41
def get_resource_id(data)
  unless data.is_a?(String)
    raise TypeError, "expected data to be an ASCII-8BIT binary String, but got a #{data.class}"
  end
  unless data.encoding == Encoding::ASCII_8BIT
    raise ArgumentError, "expected data to be an ASCII-8BIT binary String, but it was #{data.encoding} encoded"
  end

  inbuf = FFI::MemoryPointer.from_string(data)
  CTanker.tanker_get_resource_id(inbuf, data.bytesize).get_string
end
get_verification_methods() click to toggle source
# File lib/tanker/core/session.rb, line 33
def get_verification_methods # rubocop:disable Naming/AccessorMethodName
  method_list_ptr = CTanker.tanker_get_verification_methods(@ctanker).get
  count = method_list_ptr.get(:uint32, FFI::Pointer.size)

  method_base_addr = method_list_ptr.read_pointer
  method_list = count.times.map do |i|
    method_ptr = method_base_addr + i * CTanker::CVerificationMethod.size
    CTanker::CVerificationMethod.new(method_ptr).to_verification_method
  end
  CTanker.tanker_free_verification_method_list method_list_ptr
  method_list
end
register_identity(verification, options = nil) click to toggle source
# File lib/tanker/core/session.rb, line 18
def register_identity(verification, options = nil)
  cverif = CTanker::CVerification.new(verification)
  CTanker.tanker_register_identity(@ctanker, cverif, options).get_maybe_string
end
revoke_device(device_id) click to toggle source
# File lib/tanker/core/session.rb, line 63
def revoke_device(device_id)
  CTanker.tanker_revoke_device(@ctanker, device_id).get
end
set_verification_method(verification, options = nil) click to toggle source
# File lib/tanker/core/session.rb, line 28
def set_verification_method(verification, options = nil)
  cverif = CTanker::CVerification.new(verification)
  CTanker.tanker_set_verification_method(@ctanker, cverif, options).get_maybe_string
end
share(resource_ids, sharing_options) click to toggle source
# File lib/tanker/core/encryption.rb, line 53
def share(resource_ids, sharing_options)
  unless resource_ids.is_a?(Array)
    raise TypeError, "expected resource_ids to be an array of strings, but got a #{resource_ids.class}"
  end
  unless sharing_options.is_a?(SharingOptions)
    raise TypeError, "expected sharing_options to be a SharingOptions, but got a #{sharing_options.class}"
  end

  cresource_ids = CTanker.new_cstring_array resource_ids

  CTanker.tanker_share(@ctanker, cresource_ids, resource_ids.length, sharing_options).get
end
start(identity) click to toggle source
# File lib/tanker/core/session.rb, line 10
def start(identity)
  CTanker.tanker_start(@ctanker, identity).get.address
end
status() click to toggle source
# File lib/tanker/core/session.rb, line 73
def status
  CTanker.tanker_status(@ctanker)
end
stop() click to toggle source
# File lib/tanker/core/session.rb, line 69
def stop
  CTanker.tanker_stop(@ctanker).get
end
update_group_members(group_id, users_to_add: [], users_to_remove: []) click to toggle source
# File lib/tanker/core/group.rb, line 12
def update_group_members(group_id, users_to_add: [], users_to_remove: [])
  cadd_identities = CTanker.new_cstring_array users_to_add
  cremove_identities = CTanker.new_cstring_array users_to_remove
  CTanker.tanker_update_group_members(@ctanker, group_id, cadd_identities, users_to_add.length, cremove_identities,
                                      users_to_remove.length).get
end
verify_identity(verification, options = nil) click to toggle source
# File lib/tanker/core/session.rb, line 23
def verify_identity(verification, options = nil)
  cverif = CTanker::CVerification.new(verification)
  CTanker.tanker_verify_identity(@ctanker, cverif, options).get_maybe_string
end
verify_provisional_identity(verification) click to toggle source
# File lib/tanker/core/session.rb, line 85
def verify_provisional_identity(verification)
  cverif = CTanker::CVerification.new(verification)
  CTanker.tanker_verify_provisional_identity(@ctanker, cverif).get
end

Private Instance Methods

encrypt_common(data, encryption_options = nil) click to toggle source
# File lib/tanker/core/encryption.rb, line 83
def encrypt_common(data, encryption_options = nil)
  unless !encryption_options || encryption_options.is_a?(EncryptionOptions)
    raise TypeError, "expected encryption_options to be a EncryptionOptions, but got a #{encryption_options.class}"
  end

  inbuf = FFI::MemoryPointer.from_string(data)

  encrypted_size = CTanker.tanker_encrypted_size data.bytesize
  outbuf = FFI::MemoryPointer.new(:char, encrypted_size)

  CTanker.tanker_encrypt(@ctanker, outbuf, inbuf, data.bytesize, encryption_options).get

  outbuf.read_string encrypted_size
end