touchpass 0.0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +38 -0
- data/Guardfile +9 -0
- data/Rakefile +1 -0
- data/app/controllers/touchpass/verifications_controller.rb +30 -0
- data/bin/tpcli.rb +248 -0
- data/config/routes.rb +8 -0
- data/lib/engine.rb +4 -0
- data/lib/generators/templates/config/initializers/devise.rb +204 -0
- data/lib/generators/templates/config/initializers/touchpass.rb +24 -0
- data/lib/generators/templates/config/locales/devise.en.yml +53 -0
- data/lib/generators/touchpass/install_generator.rb +36 -0
- data/lib/touchpass/client.rb +431 -0
- data/lib/touchpass/crypt.rb +51 -0
- data/lib/touchpass/device.rb +18 -0
- data/lib/touchpass/key_file_creator.rb +56 -0
- data/lib/touchpass/prp.rb +256 -0
- data/lib/touchpass/verification.rb +112 -0
- data/lib/touchpass/version.rb +3 -0
- data/lib/touchpass.rb +53 -0
- data/spec/bounding_box_spec.rb +26 -0
- data/spec/geocode_spec.rb +22 -0
- data/spec/helpers/client_spec_helper.rb +1 -0
- data/spec/helpers/gtp_spec_helper.rb +98 -0
- data/spec/key_file_creator_spec.rb +30 -0
- data/spec/proximity_spec.rb +283 -0
- data/spec/prp_spec.rb +86 -0
- data/spec/resolution_spec.rb +46 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/touchpass_client_spec.rb +319 -0
- data/touchpass.gemspec +27 -0
- metadata +146 -0
@@ -0,0 +1,256 @@
|
|
1
|
+
# Use BigDecimal for accuracy
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'geocoder'
|
4
|
+
|
5
|
+
begin
|
6
|
+
# TODO: use a disk cache?
|
7
|
+
Geocoder::Configuration.cache = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
module Touchpass
|
11
|
+
module Proximity
|
12
|
+
# PRP - Privacy Respecting Proximity
|
13
|
+
# Provides mechanisms that allows locations to be compared
|
14
|
+
# for proximity without revealing the actual location of
|
15
|
+
# either party.
|
16
|
+
class PRP
|
17
|
+
|
18
|
+
class BBoxResolution
|
19
|
+
# Bounding box resolutions:
|
20
|
+
STREET = 0.001 # 3 decimal places
|
21
|
+
LOCAL = 0.01 # 2 decimal places
|
22
|
+
METRO = 0.1 # 1 decimal place
|
23
|
+
REGIONAL = 1 # 0 decimal places
|
24
|
+
end
|
25
|
+
|
26
|
+
# Minumum and maximum value for latitude
|
27
|
+
MIN_LAT, MAX_LAT = BigDecimal.new("-90.0"), BigDecimal.new("90.0")
|
28
|
+
# Minumum and maximum value for longitude
|
29
|
+
MIN_LNG, MAX_LNG = BigDecimal.new("-180.0"), BigDecimal.new("180.0")
|
30
|
+
|
31
|
+
attr_reader :lat, :lng, :resolution
|
32
|
+
attr_reader :bounding_coordinates
|
33
|
+
attr :crypted_coordinates
|
34
|
+
|
35
|
+
# Given a coordinate (latitude and longitude) and an Bounding Box resolution, return a PRP geohash
|
36
|
+
def initialize(params={})
|
37
|
+
resolution = params[:resolution]
|
38
|
+
if resolution.nil? or resolution == ""
|
39
|
+
resolution = 'LOCAL'
|
40
|
+
end
|
41
|
+
|
42
|
+
if params.has_key? :lat and params.has_key? :lng
|
43
|
+
@lat, @lng = lat, lng
|
44
|
+
elsif params[:address]
|
45
|
+
addr = nil
|
46
|
+
if params[:address].is_a? String
|
47
|
+
addr = params[:address]
|
48
|
+
elsif params[:address].is_a? Hash
|
49
|
+
addr = build_address(params[:address])
|
50
|
+
end
|
51
|
+
|
52
|
+
coord = Geocoder.coordinates(addr) if addr
|
53
|
+
#puts "addr = #{addr}"
|
54
|
+
#puts "coord = #{coord.first}, #{coord.last}"
|
55
|
+
return false if coord.nil? # Should we raise exception here?
|
56
|
+
@lat, @lng = coord.first, coord.last
|
57
|
+
end
|
58
|
+
|
59
|
+
case resolution.upcase
|
60
|
+
when 'STREET'
|
61
|
+
@resolution = BBoxResolution::STREET
|
62
|
+
when 'LOCAL'
|
63
|
+
@resolution = BBoxResolution::LOCAL
|
64
|
+
when 'METRO'
|
65
|
+
@resolution = BBoxResolution::METRO
|
66
|
+
when 'REGIONAL'
|
67
|
+
@resolution = BBoxResolution::REGIONAL
|
68
|
+
else
|
69
|
+
raise Exception, "Unknown resolution '#{resolution}'."
|
70
|
+
end
|
71
|
+
|
72
|
+
# convert lat, lng to bigdecimal
|
73
|
+
@lat, @lng = BigDecimal.new(@lat.to_s), BigDecimal.new(@lng.to_s)
|
74
|
+
|
75
|
+
# calculate bounding coordinates
|
76
|
+
calculate_bounding_coordinates!(@resolution)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Calculates four coordinates that represent an anonymised version of the location.
|
80
|
+
# Anonymised means that regardless of the absolute value of lat and lng, the four
|
81
|
+
# coordinates will be a bounding box around the point.
|
82
|
+
# Returns an array of lat/lng coordinates that bound the coordinates.
|
83
|
+
# Notes:
|
84
|
+
# Size of the bounding box is determined by the granularity parameter
|
85
|
+
def calculate_bounding_coordinates!(resolution)
|
86
|
+
return @bounding_coordinates unless @bounding_coordinates.nil?
|
87
|
+
|
88
|
+
trunc = Touchpass::Proximity::PRP.truncate_size(resolution)
|
89
|
+
granularity = BigDecimal.new(resolution.to_s)
|
90
|
+
|
91
|
+
min_lat = @lat.truncate(trunc)
|
92
|
+
min_lng = @lng.truncate(trunc)
|
93
|
+
|
94
|
+
# Allow for different calcs depending on sign of lat and lng
|
95
|
+
if @lat > 0.0
|
96
|
+
max_lat = min_lat + granularity
|
97
|
+
else
|
98
|
+
max_lat = min_lat
|
99
|
+
min_lat = max_lat - granularity
|
100
|
+
end
|
101
|
+
if @lng > 0.0
|
102
|
+
max_lng = min_lng + granularity
|
103
|
+
else
|
104
|
+
max_lng = min_lng
|
105
|
+
min_lng = max_lng - granularity
|
106
|
+
end
|
107
|
+
|
108
|
+
@bounding_coordinates = {
|
109
|
+
:top_left => [max_lat, min_lng],
|
110
|
+
:top_right => [max_lat, max_lng],
|
111
|
+
:bottom_right => [min_lat, max_lng],
|
112
|
+
:bottom_left => [min_lat, min_lng]
|
113
|
+
}
|
114
|
+
|
115
|
+
# Calibrate lats and lngs
|
116
|
+
@bounding_coordinates.collect{|k, coords| coords[0] = Touchpass::Proximity::PRP.calibrate_lat(coords[0])}
|
117
|
+
@bounding_coordinates.collect{|k, coords| coords[1] = Touchpass::Proximity::PRP.calibrate_lng(coords[1])}
|
118
|
+
|
119
|
+
return @bounding_coordinates
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns the bounding coordinates
|
123
|
+
def bounding_box
|
124
|
+
return @bounding_coordinates
|
125
|
+
end
|
126
|
+
|
127
|
+
def calibrated?
|
128
|
+
return false if @bounding_coordinates.nil? or @bounding_coordinates.empty?
|
129
|
+
for key in [:top_left, :top_right, :bottom_right, :bottom_left]
|
130
|
+
return false if !@bounding_coordinates.has_key?(key)
|
131
|
+
end
|
132
|
+
return true
|
133
|
+
end
|
134
|
+
|
135
|
+
# Test to see if the specified location is near this one, where
|
136
|
+
# 'near' means at least one of its bounding coordinates is shared between the two points
|
137
|
+
def proximate?(other_prp)
|
138
|
+
return Touchpass::Proximity::PRP.proximate?(self, other_prp)
|
139
|
+
end
|
140
|
+
|
141
|
+
def common_bounding_coordinates(other_prp)
|
142
|
+
return Touchpass::Proximity::PRP.common_bounding_coordinates(self, other_prp)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns the hashed representation of the bounding coordinates
|
146
|
+
def encrypt(salt=nil)
|
147
|
+
crypted_1 = encrypt_point(@bounding_coordinates[:top_left], salt)
|
148
|
+
crypted_2 = encrypt_point(@bounding_coordinates[:top_right], salt)
|
149
|
+
crypted_3 = encrypt_point(@bounding_coordinates[:bottom_right], salt)
|
150
|
+
crypted_4 = encrypt_point(@bounding_coordinates[:bottom_left], salt)
|
151
|
+
@crypted_coordinates = crypted_1 + crypted_2 + crypted_3 + crypted_4
|
152
|
+
return @crypted_coordinates
|
153
|
+
end
|
154
|
+
|
155
|
+
def encrypt_point(point=[], salt=nil)
|
156
|
+
return if point.size!=2
|
157
|
+
|
158
|
+
# Format lat, lng with correct decimal places
|
159
|
+
# STREET : 3 decimal places (e.g. -33.860, 151.200)
|
160
|
+
# LOCAL : 2 decimal places (e.g. -33.86, 151.20)
|
161
|
+
# METRO : 1 decimal places (e.g. -33.8, 151.2)
|
162
|
+
# REGIONAL: 0 decimal places (e.g. -33, 151)
|
163
|
+
lat = Touchpass::Proximity::PRP.format_decimal(point.first, Touchpass::Proximity::PRP.truncate_size(@resolution))
|
164
|
+
lng = Touchpass::Proximity::PRP.format_decimal(point.last, Touchpass::Proximity::PRP.truncate_size(@resolution))
|
165
|
+
|
166
|
+
# MFS: 20100722
|
167
|
+
# Original approach hashed points in the corner independently. eg:
|
168
|
+
# return crypto_provider.hexdigest(lat.to_s) + crypto_provider.hexdigest(lng.to_s)
|
169
|
+
# Changed to string concat the points together *before* the hash so that we end up with hash values
|
170
|
+
# that are coming from 3,240,000 values (ie 1,800*1,800) as opposed to 2 hashes derived from a set of 1,800
|
171
|
+
# possible values.
|
172
|
+
str_to_encrypt = (lat.to_s) + "," + (lng.to_s) + salt.to_s
|
173
|
+
return Touchpass::Crypt.encrypt(str_to_encrypt)
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.truncate_size(resolution)
|
177
|
+
split = resolution.to_s.split(".")
|
178
|
+
return split.size==1 ? 0 : split.last.size
|
179
|
+
end
|
180
|
+
|
181
|
+
# Truncate decimal (not round)
|
182
|
+
# E.g.
|
183
|
+
# format_decimal(-33.860987, 3) #=> -33.860
|
184
|
+
# format_decimal(-33.860987, 2) #=> -33.86
|
185
|
+
# format_decimal(-33.860987, 1) #=> -33.8
|
186
|
+
# format_decimal(-33.860987, 0) #=> -33
|
187
|
+
# format_decimal(151.200948, 3) #=> 151.200
|
188
|
+
# format_decimal(151.200948, 2) #=> 151.20
|
189
|
+
# format_decimal(151.200948, 1) #=> 151.2
|
190
|
+
# format_decimal(151.200948, 0) #=> 151
|
191
|
+
def self.format_decimal(decimal, decimal_places)
|
192
|
+
# KM: 20110927
|
193
|
+
# Original approach was to round decimal. eg:
|
194
|
+
# {}"%.#{decimal_places}f" % decimal
|
195
|
+
# Changed to truncate without rounding
|
196
|
+
t = 10.0 ** decimal_places
|
197
|
+
"%.#{decimal_places}f" % ((decimal * t).truncate / t)
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.calibrate_lat(lat)
|
201
|
+
if lat == 0.0
|
202
|
+
# make sure -0.0 turned into 0.0
|
203
|
+
lat = BigDecimal("0.0")
|
204
|
+
elsif !(MIN_LAT..MAX_LAT).include?(lat)
|
205
|
+
# latitude must fall within its range
|
206
|
+
lat = (lat<MIN_LAT) ? MIN_LAT : MAX_LAT
|
207
|
+
end
|
208
|
+
return lat
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.calibrate_lng(lng)
|
212
|
+
if lng == 0.0
|
213
|
+
# make sure -0.0 turned into 0.0
|
214
|
+
lng = BigDecimal("0.0")
|
215
|
+
elsif !(MIN_LNG..MAX_LNG).include?(lng)
|
216
|
+
# longitude must fall within its range
|
217
|
+
lng = (lng<MIN_LNG) ? MIN_LNG : MAX_LNG
|
218
|
+
end
|
219
|
+
return lng
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.proximate?(prp, other_prp)
|
223
|
+
return !Touchpass::Proximity::PRP.common_bounding_coordinates(prp, other_prp).empty?
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.common_bounding_coordinates(prp, other_prp)
|
227
|
+
return nil unless prp.bounding_coordinates
|
228
|
+
bounding_coords_1 = prp.bounding_coordinates.collect{|k, v| v}
|
229
|
+
bounding_coords_2 = other_prp.bounding_coordinates.collect{|k, v| v}
|
230
|
+
return bounding_coords_1 & bounding_coords_2
|
231
|
+
end
|
232
|
+
|
233
|
+
def print_bbox
|
234
|
+
for point in [:top_left, :top_right, :bottom_right, :bottom_left]
|
235
|
+
lat = Touchpass::Proximity::PRP.format_decimal(self.bounding_coordinates[point].first, Touchpass::Proximity::PRP.truncate_size(@resolution))
|
236
|
+
lng = Touchpass::Proximity::PRP.format_decimal(self.bounding_coordinates[point].last, Touchpass::Proximity::PRP.truncate_size(@resolution))
|
237
|
+
# lat = "%.#{Touchpass::Proximity::PRP.truncate_size(@resolution)}f" % self.bounding_coordinates[point].first
|
238
|
+
# lng = "%.#{Touchpass::Proximity::PRP.truncate_size(@resolution)}f" % self.bounding_coordinates[point].last
|
239
|
+
puts "#{point.to_s}: [#{lat.to_s}, #{lng.to_s}]"
|
240
|
+
end
|
241
|
+
return true
|
242
|
+
end
|
243
|
+
|
244
|
+
# Converts addresss Hash to String
|
245
|
+
# "120 Sussex Street, Sydney 2000, NSW Australia"
|
246
|
+
def build_address(attributes)
|
247
|
+
address = attributes[:address] + ","
|
248
|
+
address << " #{attributes[:city]}" if attributes[:city].present?
|
249
|
+
address << " #{attributes[:postcode]}" if attributes[:postcode].present?
|
250
|
+
address << ", #{attributes[:state]}" if attributes[:state].present?
|
251
|
+
address << " #{attributes[:country]}" if attributes[:country].present?
|
252
|
+
address
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Touchpass
|
2
|
+
module Rp
|
3
|
+
class Verification
|
4
|
+
include HTTParty
|
5
|
+
#debug_output
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
self.class.base_uri Touchpass.base_uri
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(to_party, options={})
|
12
|
+
http_options = { :body => {:to_party => to_party}, :headers => api_key_header }
|
13
|
+
|
14
|
+
# Get the verifying party devices so we can encrypt message/prp using the devices public key
|
15
|
+
device = Touchpass::Rp::Device.new
|
16
|
+
vp_devices = device.get_all(to_party)
|
17
|
+
|
18
|
+
# Generate token
|
19
|
+
token = Touchpass::Crypt.salt
|
20
|
+
hashed_token = Touchpass::Crypt.encrypt(token)
|
21
|
+
http_options[:body][:claimed_token] = hashed_token
|
22
|
+
|
23
|
+
# Encrypt token using verifying_party (to_party) devices
|
24
|
+
create_crypted_tokens(token, vp_devices, http_options)
|
25
|
+
|
26
|
+
# Generate Claimed PRP (for Location Verification)
|
27
|
+
create_prp(options[:address], vp_devices, http_options)
|
28
|
+
|
29
|
+
# Generate Claimed PRP (for Location Verification)
|
30
|
+
create_crypted_messages(options[:message], vp_devices, http_options)
|
31
|
+
|
32
|
+
response = self.class.post("/verifications.json", http_options)
|
33
|
+
return response.parsed_response
|
34
|
+
end
|
35
|
+
|
36
|
+
def cancel(id)
|
37
|
+
http_options = { :body => {}, :headers => api_key_header }
|
38
|
+
response = self.class.put("/verifications/#{id}/cancel.json", http_options)
|
39
|
+
return response.parsed_response
|
40
|
+
end
|
41
|
+
|
42
|
+
def show(id)
|
43
|
+
http_options = { :body => {}, :headers => api_key_header }
|
44
|
+
response = self.class.get("/verifications/#{id}.json", http_options)
|
45
|
+
return response.parsed_response
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def create_crypted_tokens(token, devices, http_options)
|
50
|
+
return if devices.nil? or (devices.is_a? Array and devices.empty?)
|
51
|
+
devices.each_with_index do |device, index|
|
52
|
+
device_id = device["id"]
|
53
|
+
pub_key = device["pub_key"]
|
54
|
+
public_key = Touchpass::Crypt.read_key(pub_key)
|
55
|
+
crypted_token = Base64.encode64(public_key.public_encrypt(token))
|
56
|
+
http_options[:body]["crypted_tokens[#{index}][device_id]"] = device_id
|
57
|
+
http_options[:body]["crypted_tokens[#{index}][value]"] = crypted_token
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_prp(address, devices, http_options)
|
62
|
+
return unless address.present?
|
63
|
+
|
64
|
+
http_options[:body][:location_verification] = true
|
65
|
+
|
66
|
+
# Convert address to PRP
|
67
|
+
http_options[:body][:resolution] = Touchpass.resolution # Resolution used to calculate PRP
|
68
|
+
prp = Touchpass::Proximity::PRP.new(:address => address, :resolution => Touchpass.resolution)
|
69
|
+
|
70
|
+
# Generate random salt
|
71
|
+
salt = Touchpass::Crypt.salt
|
72
|
+
|
73
|
+
# Encrypt PRP using salt
|
74
|
+
claimed_prp = prp.encrypt(salt)
|
75
|
+
http_options[:body][:claimed_prp] = claimed_prp
|
76
|
+
|
77
|
+
# Encrypt salt using verifiying_party (to_party) devices
|
78
|
+
if !devices.nil? and (devices.is_a? Array and !devices.empty?)
|
79
|
+
devices.each_with_index do |device, index|
|
80
|
+
device_id = device["id"]
|
81
|
+
pub_key = device["pub_key"]
|
82
|
+
public_key = Touchpass::Crypt.read_key(pub_key)
|
83
|
+
crypted_salt = Base64.encode64(public_key.public_encrypt(salt))
|
84
|
+
http_options[:body]["crypted_salts[#{index}][device_id]"] = device_id
|
85
|
+
http_options[:body]["crypted_salts[#{index}][value]"] = crypted_salt
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_crypted_messages(message, devices, http_options)
|
91
|
+
return if message.blank?
|
92
|
+
return if devices.nil? or (devices.is_a? Array and devices.empty?)
|
93
|
+
|
94
|
+
# Encrypt message using verifying party devices public key
|
95
|
+
devices.each_with_index do |device, index|
|
96
|
+
device_id = device["id"]
|
97
|
+
pub_key = device["pub_key"]
|
98
|
+
public_key = Touchpass::Crypt.read_key(pub_key)
|
99
|
+
crypted_message = Base64.encode64(public_key.public_encrypt(message))
|
100
|
+
http_options[:body]["crypted_messages[#{index}][device_id]"] = device_id
|
101
|
+
http_options[:body]["crypted_messages[#{index}][value]"] = crypted_message
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
def api_key_header
|
107
|
+
{ Touchpass::Client::API_KEY_HEADER => Touchpass.api_key }
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/touchpass.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "touchpass/version"
|
3
|
+
require 'touchpass/prp'
|
4
|
+
require 'touchpass/client'
|
5
|
+
require 'touchpass/crypt'
|
6
|
+
require 'touchpass/key_file_creator'
|
7
|
+
require 'touchpass/verification'
|
8
|
+
require 'touchpass/device'
|
9
|
+
|
10
|
+
module Touchpass
|
11
|
+
require 'engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
12
|
+
|
13
|
+
config = [:username, :api_key, :use_https, :host, :port, :resolution, :location_verification, :verified_message, :unverified_message]
|
14
|
+
|
15
|
+
# define getter and setter methods for each config
|
16
|
+
# normally we can use mattr_accessor :key for shortcut, but this only available in Rails environment
|
17
|
+
config.each do |symbol|
|
18
|
+
eval("@@#{symbol.to_s} = nil")
|
19
|
+
module_eval( "def self.#{symbol.to_s}() @@#{symbol.to_s}; end" )
|
20
|
+
module_eval( "def self.#{symbol.to_s}=(val) @@#{symbol.to_s} = val; end" )
|
21
|
+
end
|
22
|
+
|
23
|
+
# Default way to setup Touchpass. Run rails generate touchpass_install to create
|
24
|
+
# a fresh initializer with all configuration values.
|
25
|
+
def self.setup
|
26
|
+
yield self
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.base_uri
|
30
|
+
tp_base_uri = Touchpass.host
|
31
|
+
if Touchpass.port.present?
|
32
|
+
tp_base_uri += ":#{Touchpass.port}"
|
33
|
+
end
|
34
|
+
protocol = Touchpass.use_https ? "https://" : "http://"
|
35
|
+
tp_base_uri = protocol + tp_base_uri
|
36
|
+
end
|
37
|
+
|
38
|
+
module Role
|
39
|
+
RELYING_PARTY = "relying_party"
|
40
|
+
VERIFYING_PARTY = "verifying_party"
|
41
|
+
end
|
42
|
+
|
43
|
+
module MessagingType
|
44
|
+
APN = "apn"
|
45
|
+
APN_DEV = "apn-development"
|
46
|
+
#SMS = "sms" # not supported yet
|
47
|
+
|
48
|
+
def self.all
|
49
|
+
[APN, APN_DEV]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Bounding Box" do
|
4
|
+
|
5
|
+
context "using north of equator" do
|
6
|
+
it "should have 4 points (top_left, top_right, bottom_right, bottom_left)" do
|
7
|
+
prp = Touchpass::Proximity::PRP.new(north_of_equator)
|
8
|
+
prp.bounding_box.size.should eql(4)
|
9
|
+
for point in [:top_left, :top_right, :bottom_right, :bottom_left]
|
10
|
+
prp.bounding_box[point].should be
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "using orbitec office in sydney" do
|
16
|
+
it "should have 4 points (top_left, top_right, bottom_right, bottom_left)" do
|
17
|
+
Geocoder.should_receive(:coordinates).and_return([1, 2]) # dummy values
|
18
|
+
|
19
|
+
prp = Touchpass::Proximity::PRP.new(:address => orbitec_office)
|
20
|
+
prp.bounding_box.size.should eql(4)
|
21
|
+
for point in [:top_left, :top_right, :bottom_right, :bottom_left]
|
22
|
+
prp.bounding_box[point].should be
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Geocode" do
|
4
|
+
|
5
|
+
for address in addresses
|
6
|
+
|
7
|
+
it "should find geographic coordinates for address '#{address}'" do
|
8
|
+
dummy_lat = 10
|
9
|
+
dummy_lon = 11
|
10
|
+
|
11
|
+
# avoid hammering the geocode server
|
12
|
+
# (we just want to test Touchpass::Proximity::PRP, rather than Geocoder)
|
13
|
+
Geocoder.should_receive(:coordinates).and_return([dummy_lat, dummy_lon])
|
14
|
+
|
15
|
+
prp = Touchpass::Proximity::PRP.new(:address => address)
|
16
|
+
prp.lat.should == dummy_lat
|
17
|
+
prp.lng.should == dummy_lon
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'touchpass'
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'touchpass'
|
2
|
+
|
3
|
+
def orbitec_office
|
4
|
+
'120 Sussex St Sydney NSW 2000 Australia'
|
5
|
+
end
|
6
|
+
|
7
|
+
def apple_store_sydney
|
8
|
+
'367 George Street Sydney 2000 NSW Australia'
|
9
|
+
end
|
10
|
+
|
11
|
+
def mecca_espresso_king_st
|
12
|
+
'67 King Street Sydney 2000 NSW Australia'
|
13
|
+
end
|
14
|
+
|
15
|
+
def talga_rd_rothbury
|
16
|
+
'127 Talga Rd Rothbury NSW 2320 Australia'
|
17
|
+
end
|
18
|
+
|
19
|
+
def cessnock_post_office
|
20
|
+
'16/205 Wollombi Rd Cessnock NSW 2325 Australia'
|
21
|
+
end
|
22
|
+
|
23
|
+
def holdsworth_st_neutralbay
|
24
|
+
'2/10 Holdsworth St Neutral Bay New South Wales 2089'
|
25
|
+
end
|
26
|
+
|
27
|
+
def north_sydney_post_office
|
28
|
+
'92 Pacific Highway North Sydney NSW 2060 Australia'
|
29
|
+
end
|
30
|
+
|
31
|
+
def empire_state_building
|
32
|
+
'350 5th Avenue New York, NY 10118-3304, United States'
|
33
|
+
end
|
34
|
+
|
35
|
+
def chrysler_building
|
36
|
+
'Chrysler Building, New York, NY, United States'
|
37
|
+
end
|
38
|
+
|
39
|
+
def themet
|
40
|
+
'Metropolitan Museum of Art 5th Avenue New York NY United States'
|
41
|
+
end
|
42
|
+
|
43
|
+
def addresses
|
44
|
+
[orbitec_office, apple_store_sydney, mecca_espresso_king_st, talga_rd_rothbury, cessnock_post_office, holdsworth_st_neutralbay, north_sydney_post_office,
|
45
|
+
empire_state_building, chrysler_building, themet]
|
46
|
+
end
|
47
|
+
|
48
|
+
def resolutions
|
49
|
+
['street', 'local', 'metro', 'regional']
|
50
|
+
end
|
51
|
+
|
52
|
+
def north_of_equator
|
53
|
+
{ :lat => 0.0525, :lng => 151.2348 }
|
54
|
+
end
|
55
|
+
|
56
|
+
def south_of_equator
|
57
|
+
{ :lat => -0.0525, :lng => 151.2348 }
|
58
|
+
end
|
59
|
+
|
60
|
+
def east_of_gmt
|
61
|
+
{ :lat => 33.8, :lng => 0.0525 }
|
62
|
+
end
|
63
|
+
|
64
|
+
def west_of_gmt
|
65
|
+
{ :lat => 33.8, :lng => -0.0525 }
|
66
|
+
end
|
67
|
+
|
68
|
+
def north_west_of_equator_and_gmt
|
69
|
+
{ :lat => 0.0525, :lng => -0.0525 }
|
70
|
+
end
|
71
|
+
|
72
|
+
def north_east_of_equator_and_gmt
|
73
|
+
{ :lat => 0.0525, :lng => 0.0525 }
|
74
|
+
end
|
75
|
+
|
76
|
+
def south_east_of_equator_and_gmt
|
77
|
+
{ :lat => -0.0525, :lng => 0.0525 }
|
78
|
+
end
|
79
|
+
|
80
|
+
def south_west_of_equator_and_gmt
|
81
|
+
{ :lat => -0.0525, :lng => -0.0525 }
|
82
|
+
end
|
83
|
+
|
84
|
+
def cornercase1
|
85
|
+
{ :lat => -0.15, :lng => -0.15 }
|
86
|
+
end
|
87
|
+
|
88
|
+
def cornercase2
|
89
|
+
{ :lat => 0.15, :lng => 0.15 }
|
90
|
+
end
|
91
|
+
|
92
|
+
def cornercase3
|
93
|
+
{ :lat => 0.15, :lng => -0.15 }
|
94
|
+
end
|
95
|
+
|
96
|
+
def cornercase4
|
97
|
+
{ :lat => -0.15, :lng => 0.15 }
|
98
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Key File Creator" do
|
4
|
+
|
5
|
+
context "create public / private keys" do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@device_id = "1"
|
9
|
+
@device_udid = "747c37dc35b66830e921148398e77f3b3f5e2c3b"
|
10
|
+
@key_file_helper = Touchpass::KeyFileCreator.new(@device_id)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should initialise" do
|
14
|
+
@key_file_helper.should be
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should create public and private key files" do
|
18
|
+
@key_file_helper.generate_keys
|
19
|
+
|
20
|
+
# Read in the public and private keys from the generated files
|
21
|
+
expected_public_key = OpenSSL::PKey::RSA.new(File.read(File.join(Touchpass::KeyFileCreator.keys_path, @device_id, Touchpass::KeyFileCreator::PUBLIC_KEY))).to_s
|
22
|
+
expected_private_key = OpenSSL::PKey::RSA.new(File.read(File.join(Touchpass::KeyFileCreator.keys_path, @device_id, Touchpass::KeyFileCreator::PRIVATE_KEY))).to_s
|
23
|
+
|
24
|
+
@key_file_helper.public_key.to_s.should == expected_public_key
|
25
|
+
@key_file_helper.private_key.to_s.should == expected_private_key
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|