Module: Tanker::Identity

Defined in:
lib/tanker/identity.rb,
lib/tanker/identity/version.rb

Constant Summary collapse

APP_CREATION_NATURE =
1
APP_SECRET_SIZE =
64
APP_PUBLIC_KEY_SIZE =
32
AUTHOR_SIZE =
32
USER_SECRET_SIZE =
32
VERSION =
'3.3.0'

Class Method Summary collapse

Class Method Details

.create_identity(b64_app_id, b64_app_secret, user_id) ⇒ Object

Raises:

  • (ArgumentError)


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 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) ⇒ Object

Raises:

  • (ArgumentError)


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# 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) ⇒ Object



37
38
39
# 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) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 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) ⇒ Object



41
42
43
# File 'lib/tanker/identity.rb', line 41

def self.serialize(hash)
  Base64.strict_encode64(JSON.generate(hash))
end

.upgrade_identity(serialized_identity) ⇒ Object



132
133
134
135
136
137
138
139
140
141
# 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