Class: AppIdentity::App

Inherits:
Object
  • Object
show all
Includes:
Validation
Defined in:
lib/app_identity/app.rb

Overview

The class used by the App Identity proof generation and verification algorithms. This will typically be constructed from another object, structure, or hash, such as from a static configuration file or a database record.

AppIdentity::App objects are created frozen, and certain operations may provide a modified duplicate.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Validation

#validate_config, #validate_id, #validate_padlock, #validate_secret, #validate_version

Constructor Details

#initialize(input) ⇒ App

Constructs an AppIdentity::App from a provided object or zero-arity callable that returns an initialization object. These values should be treated as immutable objects.

The object must respond to ‘#id`, `#secret`, `#version`, and `#config` or have indexable keys (via `#[]`) of `id`, `secret`, `version`, and `config` as either Symbol or String values. That is, the `id` should be retrievable in one of the following ways:

“‘ruby input.id input input “`

If the input parameter is a callable, it will be called with no parameters to produce an input object.

The AppIdentity::App is frozen on creation.

“‘ruby AppIdentity::App.new(1, secret: “secret”, version: 1)

AppIdentity::App.new(->() { 1, secret: “secret”, version: 1 }) “‘

If the provided ‘input` is already an App and is not #verified, the existing app will be returned instead of creating a new application.



118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/app_identity/app.rb', line 118

def initialize(input)
  input = input.call if input.respond_to?(:call)

  @id = get(input, :id)
  @secret = fwrap(get(input, :secret).dup)
  @version = get(input, :version)
  @config = get(input, :config)
  @source = input
  @verified = false

  validate!
  freeze
end

Instance Attribute Details

#configObject (readonly)

An optional configuration value for validation of an App Identity proof.

If not provided, the default value when required is ‘600`, specifying that the timestamp may not differ from the current time by more than ±600 seconds (±10 minutes). Depending on the nature of the app being verified and the expected network conditions, a shorter time period than 600 seconds is recommended.

The App Identity version 1 algorithm does not use ‘config`.



82
83
84
# File 'lib/app_identity/app.rb', line 82

def config
  @config
end

#idObject (readonly)

The AppIdentity App unique identifier. Validation of the ‘id` value will convert non-string IDs using #to_s.

If using integer IDs, it is recommended that the ‘id` value be provided as some form of extended string value, such as that provided by Rails [global ID](github.com/rails/globalid). Such representations are also recommended if the ID is a compound value.

‘id` values _must not_ contain a colon (`:`) character.



34
35
36
# File 'lib/app_identity/app.rb', line 34

def id
  @id
end

#secretObject (readonly)

The App Identity app secret value. This value is used _as provided_ with no encoding or decoding. As this is a sensitive value, it may be provided as a 0-arity closure proc.

For security purposes, this is always stored as a 0-arity closure proc.



41
42
43
# File 'lib/app_identity/app.rb', line 41

def secret
  @secret
end

#sourceObject (readonly)

The original object used to construct this App Identity object.



85
86
87
# File 'lib/app_identity/app.rb', line 85

def source
  @source
end

#verifiedObject (readonly)

Whether this app was used in the successful verification of a proof.



88
89
90
# File 'lib/app_identity/app.rb', line 88

def verified
  @verified
end

#versionObject (readonly)

The positive integer version of the AppIdentity algorithm to use. Will be validated to be a supported version for app creation, and not an explicitly disallowed version during proof validation.

A string ‘version` must convert cleanly to an integer value, meaning that `“3.5”` is not a valid value.

AppIdentity algorithm versions are strictly upgradeable. That is, a version 1 app can verify version 1, 2, 3, or 4 proofs. However, a version 2 app will never validate a version 1 proof.

<table>

<thead>
  <tr>
    <th rowspan=2>Version</th>
    <th rowspan=2>Nonce</th>
    <th rowspan=2>Digest Algorithm</th>
    <th colspan=4>Can Verify</th>
  </tr>
  <tr><th>1</th><th>2</th><th>3</th><th>4</th></tr>
</thead>
<tbody>
  <tr><th>1</th><td>random</td><td>SHA 256</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
  <tr><th>2</th><td>timestamp ± fuzz</td><td>SHA 256</td><td>⛔️</td><td>✅</td><td>✅</td><td>✅</td></tr>
  <tr><th>3</th><td>timestamp ± fuzz</td><td>SHA 384</td><td>⛔️</td><td>⛔️</td><td>✅</td><td>✅</td></tr>
  <tr><th>4</th><td>timestamp ± fuzz</td><td>SHA 512</td><td>⛔️</td><td>⛔️</td><td>⛔️</td><td>✅</td></tr>
</tbody>

</table>



71
72
73
# File 'lib/app_identity/app.rb', line 71

def version
  @version
end

Class Method Details

.new(input) ⇒ Object

:nodoc:



15
16
17
18
19
20
21
# File 'lib/app_identity/app.rb', line 15

def self.new(input) # :nodoc:
  if input.is_a?(AppIdentity::App) && !input.verified
    input
  else
    super
  end
end

Instance Method Details

#==(other) ⇒ Object

:nodoc:



178
179
180
181
182
183
184
185
# File 'lib/app_identity/app.rb', line 178

def ==(other) # :nodoc:
  other.is_a?(self.class) &&
    id == other.id &&
    version == other.version &&
    config == other.config &&
    verified == other.verified &&
    secret.call == other.secret.call
end

#generate_nonce(version = nil) ⇒ Object

Generate a nonce for this application. Optionally provide a version number override to generate a compatible (upgraded) nonce version.



146
147
148
149
150
151
152
153
154
# File 'lib/app_identity/app.rb', line 146

def generate_nonce(version = nil)
  version ||= self.version

  unless self.version <= version
    raise "app version #{self.version} is not compatible with requested version #{version}"
  end

  AppIdentity::Versions[version].generate_nonce
end

#hashObject

:nodoc:



170
171
172
# File 'lib/app_identity/app.rb', line 170

def hash # :nodoc:
  [AppIdentityApp::App, id, version, config, secret]
end

#inspectObject

:nodoc:



174
175
176
# File 'lib/app_identity/app.rb', line 174

def inspect # :nodoc:
  "#<#{self.class} id: #{id} version: #{version} config: #{config} verified: #{verified}>"
end

#to_hObject Also known as: as_json

:nodoc:



156
157
158
# File 'lib/app_identity/app.rb', line 156

def to_h # :nodoc:
  {config: config, id: id, secret: secret.call, version: version}
end

#to_json(*args, **kwargs) ⇒ Object

:nodoc:



166
167
168
# File 'lib/app_identity/app.rb', line 166

def to_json(*args, **kwargs) # :nodoc:
  as_json.to_json(*args, **kwargs)
end

#to_sObject

:nodoc:



162
163
164
# File 'lib/app_identity/app.rb', line 162

def to_s # :nodoc:
  inspect
end

#unverifyObject

If the current App is ‘verified`, then return a copy of the current App with the verified flag set to `false`.



140
141
142
# File 'lib/app_identity/app.rb', line 140

def unverify
  verified ? dup.tap { |v| v.instance_variable_set(:@verified, false) }.freeze : self
end

#verifyObject

If the current App is not ‘verified`, then return a copy of the current App with the verified flag set to `true`.



134
135
136
# File 'lib/app_identity/app.rb', line 134

def verify
  verified ? self : dup.tap { |v| v.instance_variable_set(:@verified, true) }.freeze
end