toopher_api 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc 'Run tests'
8
+ task :default => :test
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/ruby
2
+ require_relative '../lib/toopher_api'
3
+
4
+ key = ENV['TOOPHER_CONSUMER_KEY']
5
+ secret = ENV['TOOPHER_CONSUMER_SECRET']
6
+ if key.empty? or secret.empty?
7
+ puts 'enter consumer credentials (set environment variables to prevent prompting):'
8
+ print 'TOOPHER_CONSUMER_KEY='
9
+ STDOUT.flush
10
+ key = gets
11
+ key.chomp!
12
+ print 'TOOPHER_CONSUMER_SECRET='
13
+ STDOUT.flush
14
+ secret = gets
15
+ secret.chomp!
16
+ end
17
+
18
+ toopher = ToopherAPI.new(key, secret)
19
+
20
+ puts 'STEP 1: Pair device'
21
+ puts 'enter pairing phrase:'
22
+ phrase = gets
23
+ phrase.chomp!
24
+ puts 'enter user name:'
25
+ user = gets
26
+ user.chomp!
27
+
28
+ pairing = toopher.pair(phrase, user)
29
+
30
+ while(!pairing['enabled'])
31
+ puts 'waiting for authorization...'
32
+ sleep(1)
33
+ pairing = toopher.get_pairing_status(pairing['id'])
34
+ end
35
+
36
+ puts 'paired successfully!'
37
+
38
+ puts 'STEP 2: Authenticate login'
39
+ puts 'enter terminal name:'
40
+ terminal_name = gets;
41
+ terminal_name.chomp!
42
+ puts 'enter action name, or [ENTER] for none:'
43
+ while (true)
44
+ action = gets;
45
+ action.chomp!
46
+
47
+ puts 'sending authentication request...'
48
+ auth = toopher.authenticate(pairing['id'], terminal_name, action)
49
+
50
+ while(auth['pending'])
51
+ puts 'waiting for authentication...'
52
+ sleep(1)
53
+ auth = toopher.get_authentication_status(auth['id'])
54
+ end
55
+
56
+ puts "Successfully authorized action '" + action + "'. Enter another action to authorize again, or [Ctrl-C] to exit"
57
+ end
58
+
@@ -0,0 +1,117 @@
1
+ =begin
2
+ Copyright (c) 2012 Toopher, Inc
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ of the Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
21
+ =end
22
+
23
+ require 'rubygems'
24
+ require 'net/http'
25
+ require 'net/https'
26
+ require 'uri'
27
+ require 'json'
28
+ require 'oauth'
29
+
30
+ class ToopherApiError < StandardError
31
+ end
32
+
33
+ class ToopherAPI
34
+
35
+ DEFAULT_BASE_URL = 'https://toopher-api.appspot.com/v1/'
36
+
37
+ def initialize(key,secret,options={}, base_url = DEFAULT_BASE_URL)
38
+ consumer_key = key
39
+ consumer_secret = secret
40
+
41
+ consumer_key.empty? and raise ArgumentError, "Toopher consumer key cannot be empty!"
42
+ consumer_secret.empty? and raise ArgumentError, "Toopher consumer secret cannot be empty!"
43
+
44
+ @base_url = base_url
45
+ @oauth_consumer = OAuth::Consumer.new(consumer_key, consumer_secret)
46
+ @oauth_options = options
47
+ end
48
+
49
+ def pair(pairing_phrase, user_name)
50
+ return make_pair_response(post('pairings/create', {
51
+ 'pairing_phrase' => pairing_phrase,
52
+ 'user_name' => user_name
53
+ }))
54
+ end
55
+
56
+ def get_pairing_status(pairing_request_id)
57
+ return make_pair_response(get('pairings/' + pairing_request_id))
58
+ end
59
+
60
+ def authenticate(pairing_id, terminal_name, action_name = '')
61
+ parameters = {
62
+ 'pairing_id' => pairing_id,
63
+ 'terminal_name' => terminal_name
64
+ }
65
+ action_name.empty? or (parameters['action_name'] = action_name)
66
+ return make_auth_response(post('authentication_requests/initiate', parameters))
67
+ end
68
+
69
+ def get_authentication_status(authentication_request_id)
70
+ return make_auth_response(get('authentication_requests/' + authentication_request_id))
71
+ end
72
+
73
+ private
74
+ def make_pair_response(result)
75
+ return {
76
+ 'id' => result['id'],
77
+ 'enabled' => result['enabled'],
78
+ 'user_id' => result['user']['id'],
79
+ 'user_name' => result['user']['name']
80
+ }
81
+ end
82
+ def make_auth_response(result)
83
+ return {
84
+ 'id' => result['id'],
85
+ 'pending' => result['pending'],
86
+ 'granted' => result['granted'],
87
+ 'automated' => result['automated'],
88
+ 'reason' => result['reason'],
89
+ 'terminal_id' => result['terminal']['id'],
90
+ 'terminal_name' => result['terminal']['name']
91
+ }
92
+ end
93
+ def post(endpoint, parameters)
94
+ url = URI.parse(@base_url + endpoint)
95
+ req = Net::HTTP::Post.new(url.path)
96
+ req.set_form_data(parameters)
97
+ return request(url, req)
98
+ end
99
+
100
+ def get(endpoint)
101
+ url = URI.parse(@base_url + endpoint)
102
+ req = Net::HTTP::Get.new(url.path)
103
+ return request(url, req)
104
+ end
105
+
106
+ def request(url, req)
107
+ http = Net::HTTP::new(url.host, url.port)
108
+ http.use_ssl = url.port == 443
109
+ req.oauth!(http, @oauth_consumer, nil, @oauth_options)
110
+ res = http.request(req)
111
+ decoded = JSON.parse(res.body)
112
+ if(decoded.has_key?("error_code"))
113
+ raise ToopherApiError, "Error code " + decoded['error_code'].to_s + ": " + decoded['error_message']
114
+ end
115
+ return decoded
116
+ end
117
+ end
@@ -0,0 +1,138 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'webmock/test_unit'
4
+ require 'toopher_api'
5
+
6
+ class TestToopher < Test::Unit::TestCase
7
+ def test_constructor()
8
+
9
+ assert_raise ArgumentError do
10
+ api = ToopherAPI.new
11
+ end
12
+
13
+ assert_raise ArgumentError do
14
+ api = ToopherAPI.new('key')
15
+ end
16
+
17
+ assert_raise ArgumentError do
18
+ api = ToopherAPI.new('', 'secret')
19
+ end
20
+
21
+ assert_nothing_raised do
22
+ api = ToopherAPI.new('key', 'secret')
23
+ end
24
+
25
+ end
26
+
27
+ def test_create_pairing_immediate_success()
28
+ stub_http_request(:post, "https://toopher-api.appspot.com/v1/pairings/create").
29
+ with(
30
+ # :headers => {
31
+ # 'Authorization' => 'OAuth oauth_consumer_key="key",oauth_nonce="nonce",oauth_signature="%2FW9rUAFDuJTTBtfSxeQ%2FDxWpVQY%3D",oauth_signature_method="HMAC-SHA1",oauth_timestamp="0",oauth_version="1.0"'
32
+ # },
33
+ :body => { 'pairing_phrase' => 'immediate_pair', 'user_name' => 'user' }
34
+ ).
35
+ to_return(
36
+ :body => '{"id":"1","enabled":true,"user":{"id":"1","name":"user"}}',
37
+ :status => 200
38
+ )
39
+
40
+ toopher = ToopherAPI.new('key', 'secret', {:nonce => 'nonce', :timestamp => '0' })
41
+ pairing = toopher.pair('immediate_pair', 'user')
42
+ assert(pairing['id'] == '1', 'bad pairing id')
43
+ assert(pairing['enabled'] == true, 'pairing not enabled')
44
+ assert(pairing['user_id'] == '1', 'bad user id')
45
+ assert(pairing['user_name'] == 'user', 'bad user name')
46
+
47
+ end
48
+ def test_get_pairing_status()
49
+ stub_http_request(:get, "https://toopher-api.appspot.com/v1/pairings/1").
50
+ to_return(
51
+ :body => '{"id":"1","enabled":true,"user":{"id":"1","name":"paired user"}}',
52
+ :status => 200
53
+ )
54
+ stub_http_request(:get, "https://toopher-api.appspot.com/v1/pairings/2").
55
+ to_return(
56
+ :body => '{"id":"2","enabled":false,"user":{"id":"2","name":"unpaired user"}}',
57
+ :status => 200
58
+ )
59
+
60
+ toopher = ToopherAPI.new('key', 'secret', {:nonce => 'nonce', :timestamp => '0' })
61
+ pairing = toopher.get_pairing_status('1')
62
+ assert(pairing['id'] == '1', 'bad pairing id')
63
+ assert(pairing['enabled'] == true, 'pairing not enabled')
64
+ assert(pairing['user_id'] == '1', 'bad user id')
65
+ assert(pairing['user_name'] == 'paired user', 'bad user name')
66
+
67
+ pairing = toopher.get_pairing_status('2')
68
+ assert(pairing['id'] == '2', 'bad pairing id')
69
+ assert(pairing['enabled'] == false, 'pairing should not be enabled')
70
+ assert(pairing['user_id'] == '2', 'bad user id')
71
+ assert(pairing['user_name'] == 'unpaired user', 'bad user name')
72
+ end
73
+
74
+ def test_create_authentication_with_no_action()
75
+ stub_http_request(:post, "https://toopher-api.appspot.com/v1/authentication_requests/initiate").
76
+ with(
77
+ :body => { 'pairing_id' => '1', 'terminal_name' => 'term name' }
78
+ ).
79
+ to_return(
80
+ :body => '{"id":"1","pending":false,"granted":true,"automated":true,"reason":"some reason","terminal":{"id":"1","name":"term name"}}',
81
+ :status => 200
82
+ )
83
+
84
+ toopher = ToopherAPI.new('key', 'secret', {:nonce => 'nonce', :timestamp => '0' })
85
+ auth = toopher.authenticate('1', 'term name')
86
+ assert(auth['id'] == '1', 'wrong auth id')
87
+ assert(auth['pending'] == false, 'wrong auth pending')
88
+ assert(auth['granted'] == true, 'wrong auth granted')
89
+ assert(auth['automated'] == true, 'wrong auth automated')
90
+ assert(auth['reason'] == 'some reason', 'wrong auth reason')
91
+ assert(auth['terminal_id'] == '1', 'wrong auth terminal id')
92
+ assert(auth['terminal_name'] == 'term name', 'wrong auth terminal name')
93
+ end
94
+
95
+ def test_get_authentication_status()
96
+ stub_http_request(:get, "https://toopher-api.appspot.com/v1/authentication_requests/1").
97
+ to_return(
98
+ :body => '{"id":"1","pending":false,"granted":true,"automated":true,"reason":"some reason","terminal":{"id":"1","name":"term name"}}',
99
+ :status => 200
100
+ )
101
+ stub_http_request(:get, "https://toopher-api.appspot.com/v1/authentication_requests/2").
102
+ to_return(
103
+ :body => '{"id":"2","pending":true,"granted":false,"automated":false,"reason":"some other reason","terminal":{"id":"2","name":"another term name"}}',
104
+ :status => 200
105
+ )
106
+
107
+ toopher = ToopherAPI.new('key', 'secret', {:nonce => 'nonce', :timestamp => '0' })
108
+ auth = toopher.get_authentication_status('1')
109
+ assert(auth['id'] == '1', 'wrong auth id')
110
+ assert(auth['pending'] == false, 'wrong auth pending')
111
+ assert(auth['granted'] == true, 'wrong auth granted')
112
+ assert(auth['automated'] == true, 'wrong auth automated')
113
+ assert(auth['reason'] == 'some reason', 'wrong auth reason')
114
+ assert(auth['terminal_id'] == '1', 'wrong auth terminal id')
115
+ assert(auth['terminal_name'] == 'term name', 'wrong auth terminal name')
116
+
117
+ auth = toopher.get_authentication_status('2')
118
+ assert(auth['id'] == '2', 'wrong auth id')
119
+ assert(auth['pending'] == true, 'wrong auth pending')
120
+ assert(auth['granted'] == false, 'wrong auth granted')
121
+ assert(auth['automated'] == false, 'wrong auth automated')
122
+ assert(auth['reason'] == 'some other reason', 'wrong auth reason')
123
+ assert(auth['terminal_id'] == '2', 'wrong auth terminal id')
124
+ assert(auth['terminal_name'] == 'another term name', 'wrong auth terminal name')
125
+ end
126
+
127
+ def test_toopher_request_error()
128
+ stub_http_request(:get, "https://toopher-api.appspot.com/v1/authentication_requests/1").
129
+ to_return(
130
+ :body => '{"error_code":401,"error_message":"Not a valid OAuth signed request"}',
131
+ :status => 401
132
+ )
133
+ toopher = ToopherAPI.new('key', 'secret', {:nonce => 'nonce', :timestamp => '0' })
134
+ assert_raise ToopherApiError do
135
+ auth = toopher.get_authentication_status('1')
136
+ end
137
+ end
138
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toopher_api
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Toopher, Inc.
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-12-05 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: oauth
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 1
29
+ segments:
30
+ - 0
31
+ - 4
32
+ - 7
33
+ version: 0.4.7
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: json
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 1
45
+ segments:
46
+ - 1
47
+ - 7
48
+ - 5
49
+ version: 1.7.5
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: webmock
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 51
61
+ segments:
62
+ - 1
63
+ - 9
64
+ - 0
65
+ version: 1.9.0
66
+ type: :development
67
+ version_requirements: *id003
68
+ description: Synchronous interface to the toopher.com authentication api.
69
+ email: support@toopher.com
70
+ executables: []
71
+
72
+ extensions: []
73
+
74
+ extra_rdoc_files: []
75
+
76
+ files:
77
+ - Rakefile
78
+ - lib/toopher_api.rb
79
+ - test/test_toopher_api.rb
80
+ - demo/toopher_demo.rb
81
+ homepage: http://toopher.org
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options: []
86
+
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ requirements: []
108
+
109
+ rubyforge_project:
110
+ rubygems_version: 1.8.24
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: Interface to the toopher.com authentication api
114
+ test_files: []
115
+