latch-sdk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6059a598c347a268972aec50301bac778e0a208a
4
+ data.tar.gz: 8f5d3b7711b4181234f56ea723d44b60ddad42d7
5
+ SHA512:
6
+ metadata.gz: 4af6bdcdbd00ddfac2571c7e1aec97989e3211c820443515a7c009bf7f52fa1658c0c09a42a85da79ba3774ff2d17fa927d4d61be8c7fcc6797cfba446abe3f0
7
+ data.tar.gz: 2220962f2845d2b9819bfe93fde77af8bb9ac367c39c3e2055a8766cc4da79e639408519e299c9dc6ccbfcdeafd62d3f0e7a7d4864c3cbecafe8227408444edf
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'latch-sdk'
6
+ s.version = '0.0.1'
7
+ s.platform = Gem::Platform::RUBY
8
+ s.summary = 'Latch SDK'
9
+ s.email = 'crresse@gmail.com'
10
+ # s.homepage = ''
11
+ s.description = s.summary
12
+ s.authors = ['Carlos Rodriguez']
13
+ s.license = 'MIT'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ # s.add_development_dependency('rake', '>= 0.9')
21
+ # s.add_development_dependency('rdoc', '>= 3')
22
+ s.add_development_dependency('rails', '>= 4.0')
23
+ # s.add_development_dependency('sqlite3')
24
+ # s.add_development_dependency('rspec-rails')
25
+ end
@@ -0,0 +1,6 @@
1
+ require 'latch/latch'
2
+ require 'latch/latch_response'
3
+ require 'latch/error'
4
+
5
+ module Latch
6
+ end
@@ -0,0 +1,45 @@
1
+ # Latch Ruby SDK - Set of reusable classes to allow developers integrate Latch on their applications.
2
+ # Copyright (C) 2013 Eleven Paths
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ module Latch
19
+ class Error
20
+ attr_reader :code
21
+ attr_reader :message
22
+
23
+ # @param string json a Json representation of an error with "code" and "message" elements
24
+ def initialize(json)
25
+ if (json.is_a?(String))
26
+ json = JSON.Parse(json)
27
+ end
28
+
29
+ if(json.has_key?("code") && json.has_key?("message"))
30
+ @code = json["code"]
31
+ @message = json["message"]
32
+ else
33
+ puts "Error creating error object from string " + json
34
+ end
35
+ end
36
+
37
+ # JSON representing the Error Object
38
+ def to_json
39
+ error = {}
40
+ error["code"] = @code
41
+ error["message"] = @message
42
+ error.to_json
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,292 @@
1
+ # Latch Ruby SDK - Set of reusable classes to allow developers integrate Latch on their applications.
2
+ # Copyright (C) 2013 Eleven Paths
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ module Latch
19
+ class Latch
20
+ attr_accessor :api_host
21
+ API_HOST = 'https://latch.elevenpaths.com'
22
+ API_VERSION = '0.9'
23
+ API_CHECK_STATUS_URL = "/api/#{API_VERSION}/status"
24
+ API_PAIR_URL = "/api/#{API_VERSION}/pair"
25
+ API_PAIR_WITH_ID_URL = "/api/#{API_VERSION}/pairWithId"
26
+ API_UNPAIR_URL = "/api/#{API_VERSION}/unpair"
27
+ API_LOCK_URL = "/api/#{API_VERSION}/lock"
28
+ API_UNLOCK_URL = "/api/#{API_VERSION}/unlock"
29
+ API_HISTORY_URL = "/api/#{API_VERSION}/history"
30
+ API_OPERATIONS_URL = "/api/#{API_VERSION}/operation"
31
+
32
+ AUTHORIZATION_HEADER_NAME = 'Authorization'
33
+ DATE_HEADER_NAME = 'X-11Paths-Date'
34
+ AUTHORIZATION_METHOD = '11PATHS'
35
+ AUTHORIZATION_HEADER_FIELD_SEPARATOR = ' '
36
+
37
+ HMAC_ALGORITHM = 'sha1'
38
+
39
+ X_11PATHS_HEADER_PREFIX = 'X-11Paths-'
40
+ X_11PATHS_HEADER_SEPARATOR = ':'
41
+
42
+ # The custom header consists of three parts, the method, the appId and the signature.
43
+ # This method returns the specified part if it exists.
44
+ # @param $part The zero indexed part to be returned
45
+ # @param $header The HTTP header value from which to extract the part
46
+ # @return string the specified part from the header or an empty string if not existent
47
+ def getPartFromHeader(part, header)
48
+ if (header.empty?)
49
+ parts = header.split(AUTHORIZATION_HEADER_FIELD_SEPARATOR)
50
+ if(parts.length > part)
51
+ return parts[part]
52
+ end
53
+ end
54
+ return ""
55
+ end
56
+
57
+ # @param $authorizationHeader Authorization HTTP Header
58
+ # @return string the Authorization method. Typical values are "Basic", "Digest" or "11PATHS"
59
+ def getAuthMethodFromHeader(authorizationHeader)
60
+ getPartFromHeader(0, authorizationHeader)
61
+ end
62
+
63
+ # @param $authorizationHeader Authorization HTTP Header
64
+ # @return string the requesting application Id. Identifies the application using the API
65
+ def getAppIdFromHeader(authorizationHeader)
66
+ getPartFromHeader(1, authorizationHeader)
67
+ end
68
+
69
+
70
+ # @param $authorizationHeader Authorization HTTP Header
71
+ # @return string the signature of the current request. Verifies the identity of the application using the API
72
+ def getSignatureFromHeader(authorizationHeader)
73
+ getPartFromHeader(2, authorizationHeader)
74
+ end
75
+
76
+
77
+ # Create an instance of the class with the Application ID and secret obtained from Eleven Paths
78
+ # @param $appId
79
+ # @param $secretKey
80
+ def initialize(appid, secret)
81
+ @appid = appid
82
+ @secret = secret
83
+ @api_host = API_HOST
84
+ end
85
+
86
+ def http(method, url, headers, params=nil)
87
+ uri = URI.parse(url)
88
+ http = Net::HTTP.new(uri.host, uri.port)
89
+
90
+ if (uri.default_port == 443)
91
+ http.use_ssl = true
92
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
93
+ end
94
+
95
+ if(method == "GET")
96
+ request = Net::HTTP::Get.new(uri.request_uri)
97
+ elsif (method == 'POST')
98
+ request = Net::HTTP::Post.new(uri.request_uri)
99
+ request.set_form_data(params)
100
+ elsif (method == "PUT")
101
+ request = Net::HTTP::Put.new(uri.request_uri)
102
+ request.set_form_data(params)
103
+ elsif (method == "DELETE")
104
+ request = Net::HTTP::Delete.new(uri.request_uri)
105
+ end
106
+
107
+ headers.map do |key,value|
108
+ request[key] = value
109
+ end
110
+
111
+ response = http.request(request)
112
+ response.body
113
+ end
114
+
115
+
116
+ def http_get_proxy(url)
117
+ LatchResponse.new(http("GET", api_host + url, authenticationHeaders('GET', url, nil)))
118
+ end
119
+
120
+ def http_post_proxy(url, params)
121
+ LatchResponse.new(http("POST", api_host + url, authenticationHeaders('POST', url, nil, nil, params), params))
122
+ end
123
+
124
+ def http_put_proxy(url, params)
125
+ LatchResponse.new(http("PUT", api_host + url, authenticationHeaders('PUT', url, nil, nil, params), params))
126
+ end
127
+
128
+ def http_delete_proxy(url)
129
+ LatchResponse.new(http("DELETE", api_host + url, authenticationHeaders('DELETE', url, nil)))
130
+ end
131
+
132
+ def pairWithId(accountId)
133
+ http_get_proxy(API_PAIR_WITH_ID_URL + '/' + accountId)
134
+ end
135
+
136
+
137
+ def pair(token)
138
+ http_get_proxy(API_PAIR_URL + '/' + token)
139
+ end
140
+
141
+
142
+ def status(accountId)
143
+ http_get_proxy(API_CHECK_STATUS_URL + '/' + accountId)
144
+ end
145
+
146
+
147
+ def operationStatus(accountId, operationId)
148
+ http_get_proxy(API_CHECK_STATUS_URL + "/" + accountId + '/op/' + operationId)
149
+ end
150
+
151
+
152
+ def unpair(accountId)
153
+ http_get_proxy(API_UNPAIR_URL + '/' + accountId)
154
+ end
155
+
156
+ def lock(accountId, operationId=nil)
157
+ if (operationId == nil)
158
+ http_post_proxy(API_LOCK_URL + '/' + accountId, {})
159
+ else
160
+ http_post_proxy(API_LOCK_URL + '/' + accountId + '/op/' + operationId, {})
161
+ end
162
+ end
163
+
164
+ def unlock(accountId, operationId=nil)
165
+ if (operationId == nil)
166
+ http_post_proxy(API_UNLOCK_URL + '/' + accountId, {})
167
+ else
168
+ http_post_proxy(API_UNLOCK_URL + '/' + accountId + '/op/' + operationId, {})
169
+ end
170
+ end
171
+
172
+ def history (accountId, from='0', to=nil)
173
+ if (to == nil)
174
+ to = Time.now.to_i*1000
175
+ end
176
+ http_get_proxy(API_HISTORY_URL + '/' + accountId + '/' + from + '/' + to.to_s)
177
+ end
178
+
179
+ def createOperation(parentId, name, twoFactor, lockOnRequest)
180
+ params = { 'parentId' => parentId, 'name' => name, 'two_factor'=>twoFactor, 'lock_on_request'=>lockOnRequest}
181
+ http_put_proxy(API_OPERATIONS_URL, params)
182
+ end
183
+
184
+ def updateOperation(operationId, name, twoFactor, lockOnRequest)
185
+ params = { 'name' => name, 'two_factor'=>twoFactor, 'lock_on_request'=>lockOnRequest}
186
+ http_post_proxy(API_OPERATIONS_URL + '/' + operationId, params)
187
+ end
188
+
189
+ def deleteOperation(operationId)
190
+ http_delete_proxy(API_OPERATIONS_URL + '/' + operationId)
191
+ end
192
+
193
+ def getOperations(operationId=nil)
194
+ if (operationId == nil)
195
+ http_get_proxy(API_OPERATIONS_URL)
196
+ else
197
+ http_get_proxy(API_OPERATIONS_URL + '/' + operationId)
198
+ end
199
+ end
200
+
201
+ # @param $data the string to sign
202
+ # @return string base64 encoding of the HMAC-SHA1 hash of the data parameter using {@code secretKey} as cipher key.
203
+ def signData(data)
204
+ Base64.encode64(OpenSSL::HMAC.digest(HMAC_ALGORITHM, @secret, data))
205
+ end
206
+
207
+
208
+ # Calculate the authentication headers to be sent with a request to the API
209
+ # @param $HTTPMethod the HTTP Method, currently only GET is supported
210
+ # @param $queryString the urlencoded string including the path (from the first forward slash) and the parameters
211
+ # @param $xHeaders HTTP headers specific to the 11-paths API. null if not needed.
212
+ # @param $utc the Universal Coordinated Time for the Date HTTP header
213
+ # @return array a map with the Authorization and Date headers needed to sign a Latch API request
214
+ def authenticationHeaders(httpMethod, queryString, xHeaders=nil, utc=nil, params=nil)
215
+ if (utc == nil)
216
+ utc = getCurrentUTC
217
+ end
218
+
219
+ stringToSign = (httpMethod.upcase).strip + "\n" +
220
+ utc.to_s + "\n" +
221
+ getSerializedHeaders(xHeaders) + "\n" +
222
+ queryString.strip
223
+
224
+ if (params != nil && params.size > 0)
225
+ serializedParams = getSerializedParams(params)
226
+ if (serializedParams != nil && serializedParams.size > 0)
227
+ stringToSign = stringToSign.strip + "\n" + serializedParams
228
+ end
229
+ end
230
+
231
+ authorizationHeader = AUTHORIZATION_METHOD +
232
+ AUTHORIZATION_HEADER_FIELD_SEPARATOR +
233
+ @appid +
234
+ AUTHORIZATION_HEADER_FIELD_SEPARATOR +
235
+ signData(stringToSign).chop
236
+
237
+ headers = {}
238
+ headers[AUTHORIZATION_HEADER_NAME] = authorizationHeader
239
+ headers[DATE_HEADER_NAME] = utc
240
+ return headers
241
+ end
242
+
243
+
244
+
245
+ # Prepares and returns a string ready to be signed from the 11-paths specific HTTP headers received
246
+ # @param $xHeaders a non necessarily ordered map of the HTTP headers to be ordered without duplicates.
247
+ # @return a String with the serialized headers, an empty string if no headers are passed, or null if there's a problem
248
+ # such as non 11paths specific headers
249
+ def getSerializedHeaders(xHeaders)
250
+ if(xHeaders != nil)
251
+ headers = xHeaders.inject({}) do |xHeaders, keys|
252
+ hash[keys[0].downcase] = keys[1]
253
+ hash
254
+ end
255
+
256
+
257
+ serializedHeaders = ''
258
+
259
+ headers.sort.map do |key,value|
260
+ if(key.downcase == X_11PATHS_HEADER_PREFIX.downcase)
261
+ puts "Error serializing headers. Only specific " + X_11PATHS_HEADER_PREFIX + " headers need to be singed"
262
+ return nil
263
+ end
264
+ serializedHeaders += key + X_11PATHS_HEADER_SEPARATOR + value + ' '
265
+ end
266
+ substitute = 'utf-8'
267
+ return serializedHeaders.gsub(/^[#{substitute}]+|[#{substitute}]+$/, '')
268
+ else
269
+ return ""
270
+ end
271
+ end
272
+
273
+ def getSerializedParams(parameters)
274
+ if (parameters != nil)
275
+ serializedParams = ''
276
+
277
+ parameters.sort.map do |key,value|
278
+ serializedParams += key + "=" + value + '&'
279
+ end
280
+ substitute = '&'
281
+ return serializedParams.gsub(/^[#{substitute}]+|[#{substitute}]+$/, '')
282
+ else
283
+ return ""
284
+ end
285
+ end
286
+
287
+ # @return a string representation of the current time in UTC to be used in a Date HTTP Header
288
+ def getCurrentUTC
289
+ Time.now.utc
290
+ end
291
+ end
292
+ end
@@ -0,0 +1,56 @@
1
+ # Latch Ruby SDK - Set of reusable classes to allow developers integrate Latch on their applications.
2
+ # Copyright (C) 2013 Eleven Paths
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ module Latch
19
+ # This class models a response from any of the endpoints in the Latch API.
20
+ # It consists of a "data" and an "error" elements. Although normally only one of them will be
21
+ # present, they are not mutually exclusive, since errors can be non fatal, and therefore a response
22
+ # could have valid information in the data field and at the same time inform of an error.
23
+ class LatchResponse
24
+ attr_accessor :data
25
+ attr_accessor :error
26
+
27
+ # @param jsonString a json string received from one of the methods of the Latch API
28
+ def initialize(jsonString)
29
+ json = JSON.parse(jsonString)
30
+
31
+ if(json != nil)
32
+ if (json.has_key?("data"))
33
+ @data = json["data"]
34
+ end
35
+
36
+ if (json.has_key?("error"))
37
+ @error = Error.new(json["error"])
38
+ end
39
+ end
40
+ end
41
+
42
+ # Get JSON String that represents the LatchResponse object
43
+ def to_json
44
+ response = {}
45
+
46
+ if (@data != nil)
47
+ response["data"] = @data
48
+ end
49
+
50
+ if (@error != nil)
51
+ response["error"] = @error.to_json
52
+ end
53
+ response.to_json
54
+ end
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: latch-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Carlos Rodriguez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ description: Latch SDK
28
+ email: crresse@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - Gemfile
34
+ - latch.gemspec
35
+ - lib/latch.rb
36
+ - lib/latch/error.rb
37
+ - lib/latch/latch.rb
38
+ - lib/latch/latch_response.rb
39
+ homepage:
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.4.5
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Latch SDK
63
+ test_files: []