tierion 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c55375f17cd7d97c88eb2121cae9b144d061a48d
4
- data.tar.gz: bb6d9e026c6efb40e5d41c801cc8d9a9bbafff81
3
+ metadata.gz: 7a6c61dbd6130591ba0ae23a7fa8845a8b2a4c8f
4
+ data.tar.gz: d7023dcf234d38ae0b383eb51ab5480d69427c41
5
5
  SHA512:
6
- metadata.gz: 938e14d5a7fb6e19fbc2edeeab3933dc85ea7c67b1718263134fd3767085ae8e221fccceed4cb39ad62cb40dca85ff8e702b97e3cb3f61a28c4f0876440406e1
7
- data.tar.gz: 36fd4e48acc7e5efa0cfec1535380ba93e82fc052b391940ac9ea6cad90a8b9a81cfd50a7a02b6114119cf67c0ec605f36ba37545f88fcf7d5a08b03a774e738
6
+ metadata.gz: 39443a1eca9208226af6a56587ba863df0428a94f647c6d82dac1cdd122109c8a192fc7fa1034e6fb11f3c72780b8d0e9bc5a0e58774ffd8447516fa3b7d3b29
7
+ data.tar.gz: 1060b935d65af04add356b0679f327cf6ce1175fc6d61cf18f93d4b3c073d4c63fbbd5e97811a81f8e366e97e6c63df8fe418fcc380dfb2bfae5bc28c02a2e30
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v1.0.0 (8/5/2016)
4
+
5
+ - Refactor Ruby API to better match the Client, HashItem, Receipt, Confirmation hierarchy.
6
+ - Support newly release Chainpoint 2.0 Blockchain receipts
7
+ - Drop support for Chainpoint 1.0
8
+
3
9
  ## v0.1.0 (8/1/2016)
4
10
 
5
11
  This is the initial ALPHA quality release.
data/README.md CHANGED
@@ -25,19 +25,21 @@ Shell commands start with a `$`, Ruby console commands start with `>`.
25
25
  Instantiate a new API client
26
26
 
27
27
  ```
28
- > t = Tierion::Hashitem.new('me@example.com', 'mypassword')
28
+ > t = Tierion::HashApi::Client.new('me@example.com', 'mypassword')
29
29
  ```
30
30
 
31
31
  You can also set the username and password in environment
32
- variables.
32
+ variables...
33
33
 
34
34
  ```
35
35
  $ export TIERION_USERNAME=me@example.com
36
36
  $ export TIERION_PASSWORD=my_pass
37
37
  ```
38
38
 
39
+ ... and call it without hardcoding your credentials.
40
+
39
41
  ```
40
- > t = Tierion::Hashitem.new
42
+ > t = Tierion::HashApi::Client.new
41
43
  ```
42
44
 
43
45
  Create the hash you want to record on the blockchain
@@ -48,93 +50,159 @@ and send it.
48
50
  => "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae">
49
51
 
50
52
  > t.send(my_hash)
51
- => Tierion::HashitemReceipt ...
53
+ => Tierion::HashApi::HashItem ...
52
54
  ```
53
55
 
54
- Examine the array of `HashitemReceipt` objects stored in the
55
- client. This is the only place to find the hash item
56
- ID's. You probably want to store these somewhere in your DB
57
- since this client is ephemeral and there is no way to
58
- retrieve these ID's later.
56
+ Now you can take a look at the Array of `HashItem`s.
59
57
 
60
58
  ```
61
- > t.receipts
62
- => [Tierion::HashitemReceipt..., Tierion::HashitemReceipt ...]
59
+ > t.hash_items
60
+ => [Tierion::HashApi::HashItem ..., Tierion::HashApi::HashItem ...]
63
61
  ```
64
62
 
65
- Get one HashitemReceipt to work on
63
+ Within the `Tierion::HashApi::HashItem` objects is the only place you
64
+ can find the hash item ID's for hashes you've sent. You will probably want
65
+ to store these somewhere in your DB since this client instance is ephemeral
66
+ and there is no way to retrieve these ID's later.
67
+
68
+ Let's grab a single `Tierion::HashApi::HashItem` to work on:
66
69
 
67
70
  ```
68
- > h = t.receipts.first
71
+ > h = t.hash_items.first
69
72
  ```
70
73
 
71
- For convenience you can use `Hashitem#time` to get
72
- the timestamp as a `Time` object (UTC time)
74
+ By default the `HashItem#timestamp` value is an Integer representing
75
+ the seconds since the UNIX epoch. For convenience you can use `HashItem#time` to get the `timestamp` as a Ruby `Time` object (UTC time).
73
76
 
74
77
  ```
78
+ > h.timestamp
79
+ => 1470448435
75
80
  > h.time
76
- => 2016-08-01 17:56:11 UTC
81
+ => 2016-08-06 01:53:55 UTC
77
82
  ```
78
83
 
79
- You can retrieve an individual `BlockchainReceipt` by
80
- passing a `HashitemReceipt` as the arg to `Hashitem#blockchain_receipt`
84
+ You can retrieve an individual `Tierion::HashApi::Receipt`
85
+ for this `HashItem` by passing the `Hashitem` instance as
86
+ an arg to `Client#receipt`
81
87
 
82
88
  ```
83
- > t.blockchain_receipt(h)
84
- => Tierion::BlockchainReceipt ...
89
+ > t.receipt(h)
90
+ => Tierion::HashApi::Receipt ...
85
91
  ```
86
92
 
87
- Or, call `Hashitem#blockchain_receipts` to loop through
88
- each `HashitemReceipt` submitted in this session
89
- and collect `BlockchainReceipts` for each from the
90
- API.
93
+ Or, call `Client#receipts` to loop through each `Hashitem`
94
+ submitted in this session and collect and cache `Receipts`
95
+ for each from the API.
91
96
 
92
- Remember that these are not available until
93
- processed and sent to the blockchain so you may need to
94
- call this again later to populate this Array fully.
97
+ Remember that `Receipt`s are not available until
98
+ processed and sent to the blockchain so you may need
99
+ to call this again to get the `Reciept` for every `HashItem`.
95
100
 
96
101
  ```
97
- > t.blockchain_receipts
98
- => [Tierion::BlockchainReceipt..., Tierion::BlockchainReceipt ...]
102
+ > t.receipts
103
+ => [Tierion::HashApi::Receipt ..., Tierion::HashApi::Receipt ...]
99
104
  ```
100
105
 
101
- Get one `BlockchainReceipt` to work on
106
+ Get one `Tierion::HashApi::Receipt` to work on
102
107
 
103
108
  ```
104
- > b = t.blockchain_receipts.first
105
- => Tierion::BlockchainReceipt ...
109
+ > r = t.receipts.first
110
+ => Tierion::HashApi::Receipt ...
106
111
  ```
107
112
 
108
- A `BlockchainReceipt` object has a number of properties
109
- which are populated from the API.
113
+ A `Tierion::HashApi::Receipt` object has a number of properties
114
+ which are populated from the API. Here is an example:
110
115
 
111
116
  ```
112
- > b.header
113
- > b.target
114
- > b.extra
115
-
116
- # The URL's that are generated for confirming this txn on the blockchain.
117
- > b.confirmation_url
118
- > b.confirmation_url_json
117
+ > r = t.receipts.first
118
+ => {
119
+ "@context"=>"https://w3id.org/chainpoint/v2",
120
+ "type"=>"ChainpointSHA256v2",
121
+ "targetHash"=>"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
122
+ "merkleRoot"=>"326c0c924a162c8637b8fa392add7c8c98f64f5194f3d2591caf88d7b0b956bd",
123
+ "proof"=>[
124
+ {
125
+ "left"=>"c108bfba805d899faa0ef53b0c064fad650249f6a648fec2bc79fd563106b1f8"
126
+ }
127
+ ],
128
+ "anchors"=>[
129
+ {
130
+ "type"=>"BTCOpReturn",
131
+ "sourceId"=>"579dce214fe0242e3397c9a988622f35b5ee91cef5068b0895a0bbe2c7797b9a"
132
+ }
133
+ ]
134
+ }
119
135
  ```
120
136
 
121
- You can also query whether the transaction associated
122
- with a `BlockchainReceipt` has actually been confirmed on the
123
- blockchain. Once confirmed a data structure from the
124
- third-party `blockchain.info` API will also be populated
125
- with the full transaction data.
137
+ The `Receipt` returns `anchors` which represent one or more trust
138
+ anchors where your hash has been stored. Currently, the only `anchor`
139
+ returned is `BTCOpReturn` which also gives you a `sourceId`
140
+ attribute. This represents the Bitcoin blockchain's OP_RETURN anchor,
141
+ with the `sourceId` representing the BTC transaction ID.
126
142
 
127
- `BlockchainReceipt`s can take quite a while to be confirmed.
143
+ You can also query whether the transaction associated with a `Receipt`
144
+ has actually been confirmed on a trust anchor with a call to
145
+ `Receipt#confirmations`. This will query each supported trust anchor
146
+ to determine whether or not the expected hash can be found. This depends
147
+ on an API call to a different third-party site for each anchor. This call
148
+ will return a hash with the supported trust anchors as the key and a `Boolean` to indicate if the confirmation was successful for that anchor.
128
149
 
150
+ `Receipt`s can take quite a while to be confirmed. Possibly several hours.
151
+ So, be patient.
152
+
153
+ ```
154
+ > r.confirmations
155
+ => {"BTCOpReturn"=>true}
129
156
  ```
130
- > b.confirmed?
131
- => true
132
157
 
133
- # A hash of data from the blockchain.info API
134
- > b.blockchain_info_confirmation
135
- => { ... }
158
+ You can of course also manually confirm that a hash is
159
+ visible at the Transaction ID (`sourceId`) appropriate
160
+ for your trust anchor. For example, for Bitcoin you can
161
+ search for the `sourceId` at a URL like:
162
+
163
+ [https://blockchain.info/tx/579dce214fe0242e3397c9a988622f35b5ee91cef5068b0895a0bbe2c7797b9a](https://blockchain.info/tx/579dce214fe0242e3397c9a988622f35b5ee91cef5068b0895a0bbe2c7797b9a)
164
+
165
+ Or just paste the transaction ID into the search field at [https://blockchain.info](https://blockchain.info).
166
+
167
+ Once you are looking at the transaction info page, you want to
168
+ look for the `OP_RETURN` part of the page, and your hash should be
169
+ there, with a `326c` prefix followed by the 32 byte (64 hex characters)
170
+ hash value you originally submitted. The prefix represents the hex values
171
+ `0x32` and `0x6c` which are the OP_RETURN special code, and the byte length in hex of the OP_RETURN value (your hash).
172
+
173
+ You can get a pretty JSON representation of the `Receipt` by calling
174
+ the `Receipt#to_pretty_json` method.
175
+
176
+ ```
177
+ > r.to_pretty_json
178
+ {
179
+ "@context": "https://w3id.org/chainpoint/v2",
180
+ "type": "ChainpointSHA256v2",
181
+ "targetHash": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
182
+ "merkleRoot": "326c0c924a162c8637b8fa392add7c8c98f64f5194f3d2591caf88d7b0b956bd",
183
+ "proof": [
184
+ {
185
+ "left": "c108bfba805d899faa0ef53b0c064fad650249f6a648fec2bc79fd563106b1f8"
186
+ }
187
+ ],
188
+ "anchors": [
189
+ {
190
+ "type": "BTCOpReturn",
191
+ "sourceId": "579dce214fe0242e3397c9a988622f35b5ee91cef5068b0895a0bbe2c7797b9a"
192
+ }
193
+ ]
194
+ }
136
195
  ```
137
196
 
197
+ You can validate this JSON representation of the receipt by
198
+ submitting it to the [Tierion validation](https://tierion.com/validate)
199
+ web page.
200
+
201
+ ## TODO
202
+
203
+ - Add blockchain receipt subscription functionality.
204
+
205
+
138
206
  ## Development
139
207
 
140
208
  After checking out the repo, run `bin/setup` to install dependencies. Then,
data/Rakefile CHANGED
@@ -5,6 +5,8 @@ Rake::TestTask.new(:test) do |t|
5
5
  t.libs << 'test'
6
6
  t.libs << 'lib'
7
7
  t.test_files = FileList['test/**/*_test.rb']
8
+ t.verbose = false
9
+ t.warning = false
8
10
  end
9
11
 
10
12
  task default: :test
@@ -7,8 +7,4 @@ require 'httparty'
7
7
  require 'hashie'
8
8
 
9
9
  require 'tierion/version'
10
- require 'tierion/hashitem'
11
- require 'tierion/hashitem_receipt'
12
- require 'tierion/blockchain_receipt'
13
- require 'tierion/blockchain_receipt_header'
14
- require 'tierion/blockchain_receipt_target'
10
+ require 'tierion/hash_api'
@@ -0,0 +1,3 @@
1
+ require 'tierion/hash_api/client'
2
+ require 'tierion/hash_api/hash_item'
3
+ require 'tierion/hash_api/receipt'
@@ -0,0 +1,145 @@
1
+ module Tierion
2
+ module HashApi
3
+ class Client
4
+ include ::HTTParty
5
+ base_uri 'https://hashapi.tierion.com/v1'
6
+
7
+ default_timeout 5
8
+ open_timeout 5
9
+ # debug_output $stdout
10
+
11
+ attr_accessor :hash_items
12
+
13
+ def initialize(uname = ENV['TIERION_USERNAME'], pwd = ENV['TIERION_PASSWORD'])
14
+ @auth = { username: uname, password: pwd }
15
+ @access_token = nil
16
+ @expires_at = Time.now.utc - 1
17
+ @refresh_token = nil
18
+ @hash_items = []
19
+ auth
20
+ end
21
+
22
+ def auth
23
+ options = { body: @auth }
24
+ response = self.class.post('/auth/token', options)
25
+
26
+ if response.success?
27
+ extract_auth_tokens(response)
28
+ else
29
+ raise_error(response)
30
+ end
31
+ end
32
+
33
+ def auth_refresh
34
+ if expired_auth?
35
+ options = { body: { 'refreshToken' => @refresh_token } }
36
+ response = self.class.post('/auth/refresh', options)
37
+
38
+ if response.success?
39
+ extract_auth_tokens(response)
40
+ else
41
+ raise_error(response)
42
+ end
43
+ else
44
+ auth
45
+ end
46
+ end
47
+
48
+ def send(hash)
49
+ unless hash =~ /^[a-f0-9]{64}$/
50
+ raise ArgumentError, 'is not a valid SHA256 hex hash string'
51
+ end
52
+
53
+ auth_refresh unless logged_in?
54
+ options = {
55
+ body: { 'hash' => hash },
56
+ headers: { 'Authorization' => "Bearer #{@access_token}" }
57
+ }
58
+ response = self.class.post('/hashitems', options)
59
+
60
+ if response.success?
61
+ parsed = response.parsed_response
62
+ Hashie.symbolize_keys!(parsed)
63
+ parsed.merge!({hash: hash})
64
+ h = Tierion::HashApi::HashItem.new(parsed)
65
+ @hash_items << h
66
+ return h
67
+ else
68
+ raise_error(response)
69
+ end
70
+ end
71
+
72
+ # Get a Receipt for each HashItem that doesn't have one
73
+ # and return the collection of Receipts.
74
+ def receipts
75
+ @hash_items.each do |h|
76
+ next if h.receipt.present?
77
+ h.receipt = receipt(h)
78
+ end
79
+
80
+ @hash_items.collect(&:receipt).compact
81
+ end
82
+
83
+ # Retrieve the receipt for a specific HashItem
84
+ def receipt(h)
85
+ unless h.is_a?(Tierion::HashApi::HashItem)
86
+ raise ArgumentError, 'is not a Tierion::HashApi::HashItem object'
87
+ end
88
+
89
+ auth_refresh unless logged_in?
90
+ options = { headers: { 'Authorization' => "Bearer #{@access_token}" } }
91
+ response = self.class.get("/receipts/#{h.id}", options)
92
+
93
+ if response.success? && response.parsed_response['receipt'].present?
94
+ receipt = JSON.parse(response.parsed_response['receipt'])
95
+ Hashie.symbolize_keys!(receipt)
96
+
97
+ if receipt.key?(:type) || receipt.key?('@type')
98
+ Tierion::HashApi::Receipt.new(receipt)
99
+ else
100
+ raise 'Invalid Receipt found'
101
+ end
102
+ else
103
+ return nil
104
+ end
105
+ end
106
+
107
+ def logged_in?
108
+ @access_token.present? &&
109
+ @refresh_token.present? &&
110
+ @expires_at >= Time.now.utc
111
+ end
112
+
113
+ private
114
+
115
+ def raise_error(response)
116
+ if response['error'].present?
117
+ raise response['error']
118
+ else
119
+ raise 'Unknown Fatal Error'
120
+ end
121
+ end
122
+
123
+
124
+ def expired_auth?
125
+ @access_token.present? &&
126
+ @refresh_token.present? &&
127
+ @expires_at < Time.now.utc
128
+ end
129
+
130
+ def extract_auth_tokens(resp)
131
+ if resp &&
132
+ resp.parsed_response &&
133
+ resp.parsed_response.is_a?(Hash) &&
134
+ resp.parsed_response.key?('access_token') &&
135
+ resp.parsed_response.key?('refresh_token') &&
136
+ resp.parsed_response.key?('expires_in')
137
+ @access_token = resp.parsed_response['access_token']
138
+ @refresh_token = resp.parsed_response['refresh_token']
139
+ @expires_at = Time.now.utc + resp.parsed_response['expires_in']
140
+ return true
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,16 @@
1
+ module Tierion
2
+ module HashApi
3
+ class HashItem < Hashie::Dash
4
+ include Hashie::Extensions::Dash::PropertyTranslation
5
+
6
+ property :hash, required: true
7
+ property :id, from: :receiptId, required: true
8
+ property :timestamp, required: true
9
+ property :receipt, required: false, default: nil
10
+
11
+ def time
12
+ timestamp.is_a?(Integer) ? Time.at(timestamp).utc : nil
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ module Tierion
2
+ module HashApi
3
+ class Receipt < Hash
4
+ include Hashie::Extensions::MergeInitializer
5
+ include Hashie::Extensions::MethodAccess
6
+ include Hashie::Extensions::IndifferentAccess
7
+
8
+ def to_pretty_json
9
+ puts JSON.pretty_generate(self)
10
+ end
11
+
12
+ def confirmations
13
+ get_confirmations
14
+ @confs
15
+ end
16
+
17
+ private
18
+
19
+ def get_confirmations
20
+ @confs = {} if @confs.blank?
21
+
22
+ return {} if anchors.blank?
23
+
24
+ anchors.each do |a|
25
+ # allready confirmed this anchor
26
+ next if @confs[a['type']].is_a?(TrueClass)
27
+
28
+ case a['type']
29
+ when 'BTCOpReturn'
30
+ # txn_id
31
+ if a['sourceId'].present?
32
+ @confs[a['type']] = btc_op_return_confirmed?(a['sourceId'])
33
+ end
34
+ end
35
+ end
36
+
37
+ @confs
38
+ end
39
+
40
+ # Confirm Bitcoin OP_RETURN anchor
41
+ def btc_op_return_confirmed?(source_id)
42
+ url = "https://blockchain.info/tx-index/#{source_id}?format=json"
43
+
44
+ # op_return values begin with 0x6a (op_return code) &
45
+ # 0x20 (length in hex : 32 bytes)
46
+ op_return = ['6a20', merkleRoot].join('')
47
+
48
+ response = HTTParty.get(url)
49
+
50
+ if response.success? && response['out'].present?
51
+ has_op_return = response['out'].any? do |o|
52
+ o['script'].present? && o['script'] == op_return
53
+ end
54
+
55
+ return has_op_return
56
+ else
57
+ false
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,3 +1,3 @@
1
1
  module Tierion
2
- VERSION = '0.1.0'
2
+ VERSION = '1.0.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tierion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glenn Rempe
@@ -30,7 +30,7 @@ cert_chain:
30
30
  zieXiXZSAojfFx9g91fKdIrlPbInHU/BaCxXSLBwvOM0drE+c2ue9X8gB55XAhzX
31
31
  37oBiw==
32
32
  -----END CERTIFICATE-----
33
- date: 2016-08-02 00:00:00.000000000 Z
33
+ date: 2016-08-06 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: httparty
@@ -154,11 +154,10 @@ files:
154
154
  - certs/gem-public_cert_grempe.pem
155
155
  - exe/tierion
156
156
  - lib/tierion.rb
157
- - lib/tierion/blockchain_receipt.rb
158
- - lib/tierion/blockchain_receipt_header.rb
159
- - lib/tierion/blockchain_receipt_target.rb
160
- - lib/tierion/hashitem.rb
161
- - lib/tierion/hashitem_receipt.rb
157
+ - lib/tierion/hash_api.rb
158
+ - lib/tierion/hash_api/client.rb
159
+ - lib/tierion/hash_api/hash_item.rb
160
+ - lib/tierion/hash_api/receipt.rb
162
161
  - lib/tierion/version.rb
163
162
  - tierion.gemspec
164
163
  homepage: https://github.com/grempe/tierion
metadata.gz.sig CHANGED
Binary file
@@ -1,62 +0,0 @@
1
- module Tierion
2
- class BlockchainReceipt < Hashie::Dash
3
- include Hashie::Extensions::Dash::PropertyTranslation
4
-
5
- property :header, required: true, transform_with: ->(v) {
6
- BlockchainReceiptHeader.new(v)
7
- }
8
-
9
- property :target, required: true, transform_with: ->(v) {
10
- BlockchainReceiptTarget.new(v)
11
- }
12
-
13
- property :extra, required: false, default: []
14
-
15
- property :blockchain_info_confirmation, required: false, default: nil
16
-
17
- # Output clean JSON in a format that works with the Blockchain
18
- # Receipt validator at https://tierion.com/validate
19
- def to_pretty_json
20
- puts JSON.pretty_generate(self)
21
- end
22
-
23
- # Recalculate the merkle tree to ensure the receipt is valid
24
- def valid?
25
- # TODO
26
- end
27
-
28
- # Make an API call to check if the tx_id is a confirmed Transaction
29
- # on the Blockchain and contains the expected OP_RETURN value with
30
- # the merkle_root from this receipt.
31
- def confirmed?
32
- return false if header.blank? || header.tx_id.blank?
33
- return false if header.merkle_root.blank?
34
- response = HTTParty.get(confirmation_url_json)
35
-
36
- if response.success? && response['out'].present?
37
- # op_return values begin with 0x6a (op_return code) &
38
- # 0x20 (hex length in bytes of string)
39
- expected_op_return_value = ['6a20', header.merkle_root].join('')
40
- confirmed = response['out'].any? do |o|
41
- o['script'].present? && o['script'] == expected_op_return_value
42
- end
43
-
44
- # store the parsed output from blockchain.info
45
- self.blockchain_info_confirmation = response.parsed_response if confirmed
46
- return confirmed
47
- else
48
- false
49
- end
50
- end
51
-
52
- def confirmation_url
53
- return nil if header.blank? || header.tx_id.blank?
54
- "https://blockchain.info/tx-index/#{header.tx_id}"
55
- end
56
-
57
- def confirmation_url_json
58
- return nil if header.blank? || header.tx_id.blank?
59
- "#{confirmation_url}?format=json"
60
- end
61
- end
62
- end
@@ -1,11 +0,0 @@
1
- module Tierion
2
- class BlockchainReceiptHeader < Hashie::Dash
3
- include Hashie::Extensions::Dash::PropertyTranslation
4
-
5
- property :chainpoint_version, required: true
6
- property :hash_type, required: true
7
- property :merkle_root, required: true
8
- property :tx_id, required: true
9
- property :timestamp, required: true
10
- end
11
- end
@@ -1,9 +0,0 @@
1
- module Tierion
2
- class BlockchainReceiptTarget < Hashie::Dash
3
- include Hashie::Extensions::Dash::PropertyTranslation
4
-
5
- property :target_hash, required: true
6
- property :target_proof, required: true
7
- property :target_uri, required: false
8
- end
9
- end
@@ -1,138 +0,0 @@
1
- module Tierion
2
- class Hashitem
3
- include ::HTTParty
4
- base_uri 'https://hashapi.tierion.com/v1'
5
-
6
- default_timeout 5
7
- open_timeout 5
8
- # debug_output $stdout
9
-
10
- attr_reader :receipts
11
- attr_accessor :debug
12
-
13
- def initialize(uname = ENV['TIERION_USERNAME'], pwd = ENV['TIERION_PASSWORD'])
14
- @auth = { username: uname, password: pwd }
15
- @access_token = nil
16
- @expires_at = Time.now.utc - 1
17
- @refresh_token = nil
18
- @receipts = []
19
- auth
20
- end
21
-
22
- def auth
23
- options = { body: @auth }
24
- response = self.class.post('/auth/token', options)
25
-
26
- if response.success?
27
- extract_auth_tokens(response)
28
- else
29
- raise_error(response)
30
- end
31
- end
32
-
33
- def auth_refresh
34
- if expired_auth?
35
- options = { body: { 'refreshToken' => @refresh_token } }
36
- response = self.class.post('/auth/refresh', options)
37
-
38
- if response.success?
39
- extract_auth_tokens(response)
40
- else
41
- raise_error(response)
42
- end
43
- else
44
- auth
45
- end
46
- end
47
-
48
- def send(hash)
49
- unless hash =~ /^[a-f0-9]{64}$/
50
- raise ArgumentError, 'is not a valid SHA256 hex hash string'
51
- end
52
-
53
- auth_refresh unless logged_in?
54
- options = {
55
- body: { 'hash' => hash },
56
- headers: { 'Authorization' => "Bearer #{@access_token}" }
57
- }
58
- response = self.class.post('/hashitems', options)
59
-
60
- if response.success?
61
- parsed = response.parsed_response
62
- Hashie.symbolize_keys!(parsed)
63
- hir = HashitemReceipt.new(parsed)
64
- @receipts << hir
65
- return hir
66
- else
67
- raise_error(response)
68
- end
69
- end
70
-
71
- # Retrieve and store the BlockchainReceipt from the API for each
72
- # HashitemReceipt that does not have one.
73
- def blockchain_receipts
74
- @receipts.each do |hir|
75
- next if hir.blockchain_receipt.is_a?(Tierion::BlockchainReceipt)
76
- bcr = blockchain_receipt(hir)
77
- hir.blockchain_receipt = bcr
78
- end
79
-
80
- @receipts.collect(&:blockchain_receipt).compact
81
- end
82
-
83
- # Retrieve the blockchain receipt for a specific HashitemReceipt ID
84
- def blockchain_receipt(hir)
85
- unless hir.is_a?(Tierion::HashitemReceipt)
86
- raise ArgumentError, 'is not a HashitemReceipt object'
87
- end
88
-
89
- auth_refresh unless logged_in?
90
- options = { headers: { 'Authorization' => "Bearer #{@access_token}" } }
91
- response = self.class.get("/receipts/#{hir.id}", options)
92
-
93
- if response.success? && response.parsed_response['receipt'].present?
94
- receipt = JSON.parse(response.parsed_response['receipt'])
95
- Hashie.symbolize_keys!(receipt)
96
- BlockchainReceipt.new(receipt)
97
- else
98
- return nil
99
- end
100
- end
101
-
102
- private
103
-
104
- def raise_error(response)
105
- if response['error'].present?
106
- raise response['error']
107
- else
108
- raise 'Unknown Fatal Error'
109
- end
110
- end
111
-
112
- def logged_in?
113
- @access_token.present? &&
114
- @refresh_token.present? &&
115
- @expires_at >= Time.now.utc
116
- end
117
-
118
- def expired_auth?
119
- @access_token.present? &&
120
- @refresh_token.present? &&
121
- @expires_at < Time.now.utc
122
- end
123
-
124
- def extract_auth_tokens(resp)
125
- if resp &&
126
- resp.parsed_response &&
127
- resp.parsed_response.is_a?(Hash) &&
128
- resp.parsed_response.key?('access_token') &&
129
- resp.parsed_response.key?('refresh_token') &&
130
- resp.parsed_response.key?('expires_in')
131
- @access_token = resp.parsed_response['access_token']
132
- @refresh_token = resp.parsed_response['refresh_token']
133
- @expires_at = Time.now.utc + resp.parsed_response['expires_in']
134
- return true
135
- end
136
- end
137
- end
138
- end
@@ -1,13 +0,0 @@
1
- module Tierion
2
- class HashitemReceipt < Hashie::Dash
3
- include Hashie::Extensions::Dash::PropertyTranslation
4
-
5
- property :id, from: :receiptId, required: true
6
- property :timestamp, required: true
7
- property :blockchain_receipt, required: false, default: nil
8
-
9
- def time
10
- timestamp.is_a?(Integer) ? Time.at(timestamp).utc : nil
11
- end
12
- end
13
- end