module Tanker::Identity
Constants
- APP_CREATION_NATURE
- APP_PUBLIC_KEY_SIZE
- APP_SECRET_SIZE
- AUTHOR_SIZE
- USER_SECRET_SIZE
- VERSION
Public Class Methods
create_identity(b64_app_id, b64_app_secret, user_id)
click to toggle source
# File lib/tanker/identity.rb, line 45 def self.create_identity(b64_app_id, b64_app_secret, user_id) assert_string_values({ app_id: b64_app_id, app_secret: b64_app_secret, user_id: user_id }) app_id = Base64.strict_decode64(b64_app_id) app_secret = Base64.strict_decode64(b64_app_secret) raise ArgumentError, "Invalid app_id" if app_id.bytesize != Crypto::BLOCK_HASH_SIZE raise ArgumentError, "Invalid app_secret" if app_secret.bytesize != APP_SECRET_SIZE raise ArgumentError, "Invalid (app_id, app_secret) combination" if app_id != generate_app_id(app_secret) hashed_user_id = Crypto.hash_user_id(app_id, user_id) signature_keypair = Crypto.generate_signature_keypair message = signature_keypair[:public_key] + hashed_user_id signature = Crypto.sign_detached(message, app_secret) serialize({ trustchain_id: Base64.strict_encode64(app_id), target: 'user', value: Base64.strict_encode64(hashed_user_id), delegation_signature: Base64.strict_encode64(signature), ephemeral_public_signature_key: Base64.strict_encode64(signature_keypair[:public_key]), ephemeral_private_signature_key: Base64.strict_encode64(signature_keypair[:private_key]), user_secret: Base64.strict_encode64(user_secret(hashed_user_id)) }) end
create_provisional_identity(b64_app_id, target, value)
click to toggle source
# File lib/tanker/identity.rb, line 75 def self.create_provisional_identity(b64_app_id, target, value) assert_string_values({ app_id: b64_app_id, target: target, value: value }) valid_targets = %w[email phone_number] unless valid_targets.include? target raise ArgumentError, "expected #{target} to be one of #{valid_targets.join(', ')}" end app_id = Base64.strict_decode64(b64_app_id) raise ArgumentError, "Invalid app_id" if app_id.bytesize != Crypto::BLOCK_HASH_SIZE encryption_keypair = Crypto.generate_encryption_keypair signature_keypair = Crypto.generate_signature_keypair serialize({ trustchain_id: b64_app_id, target: target, value: value, public_encryption_key: Base64.strict_encode64(encryption_keypair[:public_key]), private_encryption_key: Base64.strict_encode64(encryption_keypair[:private_key]), public_signature_key: Base64.strict_encode64(signature_keypair[:public_key]), private_signature_key: Base64.strict_encode64(signature_keypair[:private_key]) }) end
deserialize(b64_json)
click to toggle source
# File lib/tanker/identity.rb, line 37 def self.deserialize(b64_json) JSON.parse(Base64.strict_decode64(b64_json)) end
get_public_identity(serialized_identity)
click to toggle source
# File lib/tanker/identity.rb, line 104 def self.get_public_identity(serialized_identity) assert_string_values({ identity: serialized_identity }) identity = deserialize(serialized_identity) if identity['target'] == 'user' public_keys = ['trustchain_id', 'target', 'value'] else public_keys = ['trustchain_id', 'target', 'value', 'public_encryption_key', 'public_signature_key'] end public_identity = {} public_keys.each { |key| public_identity[key] = identity.fetch(key) } if identity['target'] == 'email' public_identity['target'] = 'hashed_email' public_identity['value'] = Crypto.hashed_provisional_email(public_identity['value']) elsif identity['target'] != 'user' public_identity['target'] = 'hashed_' + public_identity['target'] public_identity['value'] = Crypto.hashed_provisional_value(public_identity['value'], identity['private_signature_key']) end serialize(public_identity) rescue KeyError # failed fetch raise ArgumentError, 'Not a valid Tanker identity' end
serialize(hash)
click to toggle source
# File lib/tanker/identity.rb, line 41 def self.serialize(hash) Base64.strict_encode64(JSON.generate(hash)) end
upgrade_identity(serialized_identity)
click to toggle source
# File lib/tanker/identity.rb, line 132 def self.upgrade_identity(serialized_identity) assert_string_values({ identity: serialized_identity }) identity = deserialize(serialized_identity) if identity['target'] == 'email' && !identity.key?('private_encryption_key') identity['target'] = 'hashed_email' identity['value'] = Crypto.hashed_provisional_email(identity['value']) end serialize(identity) end
Private Class Methods
assert_string_values(hash)
click to toggle source
# File lib/tanker/identity.rb, line 22 def self.assert_string_values(hash) hash.each_pair do |key, value| raise TypeError, "expected #{key} to be a String but was a #{value.class}" unless value.is_a?(String) end end
generate_app_id(app_secret)
click to toggle source
# File lib/tanker/identity.rb, line 28 def self.generate_app_id(app_secret) block_nature = APP_CREATION_NATURE.chr(Encoding::ASCII_8BIT) none_author = 0.chr(Encoding::ASCII_8BIT) * AUTHOR_SIZE app_public_key = app_secret[-APP_PUBLIC_KEY_SIZE..-1] Crypto.generichash(block_nature + none_author + app_public_key, Crypto::BLOCK_HASH_SIZE) end
user_secret(hashed_user_id)
click to toggle source
# File lib/tanker/identity.rb, line 16 def self.user_secret(hashed_user_id) random_bytes = Crypto.random_bytes(USER_SECRET_SIZE - 1) check = Crypto.generichash(random_bytes + hashed_user_id, Crypto::HASH_MIN_SIZE) random_bytes + check[0] end