mobile-subscriber 1.0.0.alpha4 → 1.0.0.alpha5

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mobile-subscriber.rb +13 -3
  3. data/lib/mobile_subscriber/dictionaries/dialing_and_country_codes.rb +468 -28
  4. data/lib/mobile_subscriber/http/known_imsi_headers.rb +22 -0
  5. data/lib/mobile_subscriber/http/known_msisdn_headers.rb +68 -0
  6. data/lib/mobile_subscriber/http/request_info.rb +166 -0
  7. data/lib/mobile_subscriber/identity.rb +97 -1
  8. data/lib/mobile_subscriber/version.rb +1 -1
  9. data/mobile_subscriber.thor +41 -0
  10. data/spec/factories/mobile_requests.rb +28 -0
  11. data/spec/factories/mobile_requests_from_claro.rb +257 -0
  12. data/spec/factories/mobile_requests_from_iusacell.rb +13 -0
  13. data/spec/factories/mobile_requests_from_movistar.rb +15 -0
  14. data/spec/factories/mobile_requests_from_telcel.rb +14 -0
  15. data/spec/factories/mobile_requests_from_vivo.rb +13 -0
  16. data/spec/features/claro_user_detection_spec.rb +170 -0
  17. data/spec/features/iusacell_user_detection_spec.rb +19 -0
  18. data/spec/features/movistar_user_detection_spec.rb +19 -0
  19. data/spec/features/telcel_user_detection_spec.rb +19 -0
  20. data/spec/models/{isdn_spec.rb → identity_spec.rb} +5 -5
  21. data/spec/shared_examples/identity_detection_in_argentina.rb +11 -0
  22. data/spec/shared_examples/identity_detection_in_brazil.rb +12 -0
  23. data/spec/shared_examples/identity_detection_in_chile.rb +12 -0
  24. data/spec/shared_examples/identity_detection_in_colombia.rb +12 -0
  25. data/spec/shared_examples/identity_detection_in_costa_rica.rb +15 -0
  26. data/spec/shared_examples/identity_detection_in_dominican_republic.rb +12 -0
  27. data/spec/shared_examples/identity_detection_in_ecuador.rb +12 -0
  28. data/spec/shared_examples/identity_detection_in_el_salvador.rb +15 -0
  29. data/spec/shared_examples/identity_detection_in_guatemala.rb +15 -0
  30. data/spec/shared_examples/identity_detection_in_honduras.rb +11 -0
  31. data/spec/shared_examples/identity_detection_in_mexico.rb +11 -0
  32. data/spec/shared_examples/identity_detection_in_nicaragua.rb +12 -0
  33. data/spec/shared_examples/identity_detection_in_panama.rb +12 -0
  34. data/spec/shared_examples/identity_detection_in_peru.rb +12 -0
  35. data/spec/shared_examples/identity_detection_in_puerto_rico.rb +14 -0
  36. data/spec/shared_examples/of_msisdn_detection_from_http_request.rb +3 -188
  37. data/templates/dialing_and_country_codes.rb.erb +20 -0
  38. metadata +58 -28
  39. data/lib/mobile_subscriber/detection/from_msisdn_http_request_header.rb +0 -48
  40. data/lib/mobile_subscriber/detection/from_x_nokia_msisdn_http_request_header.rb +0 -58
  41. data/lib/mobile_subscriber/detection/from_x_up_calling_line_id_http_request_header.rb +0 -65
  42. data/lib/mobile_subscriber/detection/from_x_up_ch_msisdn_http_request_header.rb +0 -35
  43. data/lib/mobile_subscriber/detection/from_x_up_subno_http_request_header.rb +0 -44
  44. data/lib/mobile_subscriber/detection/from_x_wap_msisdn_http_request_header.rb +0 -37
  45. data/lib/mobile_subscriber/detection/from_x_wap_sesiones3g_mdn_http_request_header.rb +0 -39
  46. data/lib/mobile_subscriber/detection/from_x_ztgo_beareraddress_http_request_header.rb +0 -36
  47. data/lib/mobile_subscriber/detection/http_request_info.rb +0 -77
  48. data/lib/mobile_subscriber/isdn.rb +0 -89
  49. data/spec/detection/from_msisdn_http_request_header_spec.rb +0 -53
  50. data/spec/detection/from_x_nokia_msisdn_http_request_header_spec.rb +0 -99
  51. data/spec/detection/from_x_up_calling_line_id_http_request_header_spec.rb +0 -39
  52. data/spec/detection/from_x_up_subno_http_request_header_spec.rb +0 -43
  53. data/spec/detection/from_x_wap_msisdn_http_request_header_spec.rb +0 -32
  54. data/spec/detection/from_x_wap_sesiones3g_mdn_http_request_header_spec.rb +0 -29
  55. data/spec/factories/requests.rb +0 -229
@@ -0,0 +1,22 @@
1
+ module MobileSubscriber::HTTP
2
+
3
+ # Known IMSI Header and MCC/MNC Tuples:
4
+ KNOWN_IMSI_HEADER_MCC_MNC = {
5
+
6
+ 'X-Imsi' => [
7
+ ['714', '03'], # Claro Panamá
8
+ ],
9
+
10
+ 'X-Nokia-Imsi' => [
11
+ ['704', '01' ], # Claro Guatemala
12
+ ['716', '10' ], # Claro Perú
13
+ ['722', '310'], # Claro Argentina
14
+ ['722', '320'], # Claro Argentina
15
+ ['722', '330'], # Claro Argentina
16
+ ],
17
+
18
+ 'X-Cisco-Imsi' => [
19
+ ['330', '110'], # Claro Puerto Rico
20
+ ]
21
+ }
22
+ end
@@ -0,0 +1,68 @@
1
+ module MobileSubscriber::HTTP
2
+
3
+ KNOWN_MSISDN_HEADER_MCC_MNC = {
4
+
5
+ 'Msisdn' => [
6
+ ['370', '02'], # Claro República Dominicana
7
+ ['714', '03'], # Claro Paraguay
8
+ ['724', '05'], # Claro Brasil A
9
+ ['724', '38'], # Claro Brasil B
10
+ ['740', '01'], # Claro Ecuador
11
+ ],
12
+
13
+ 'X-Cisco-Msisdn' => [
14
+ ['330', '110'], # Claro Puerto Rico
15
+ ],
16
+
17
+ 'X-Nokia-Msisdn' => [
18
+ ['334', '020'], # Telcel México
19
+ ['704', '01' ], # Claro Guatemala
20
+ ['706', '01' ], # Claro El Salvador
21
+ ['708', '001'], # Claro Honduras
22
+ ['710', '21' ], # Claro Nicaragua
23
+ ['712', '03' ], # Claro Costa Rica
24
+ ['722', '310'], # Claro Argentina A
25
+ ['722', '320'], # Claro Argentina B
26
+ ['722', '330'], # Claro Argentina C
27
+ ],
28
+
29
+ 'X-Up-Calling-Line-Id' => [
30
+ ['334', '030'], # Movistar México
31
+ ['716', '06' ], # Movistar Perú
32
+ ['716', '10' ], # Claro Perú
33
+ ['722', '010'], # Movistar Argentina
34
+ ['722', '070'], # Movistar Argentina
35
+ ['724', '02' ], # TIM (Telecom Italia Mobile) Brasil A
36
+ ['724', '03' ], # TIM (Telecom Italia Mobile) Brasil B
37
+ ['724', '04' ], # TIM (Telecom Italia Mobile) Brasil C
38
+ ['724', '30' ], # OI Brasil
39
+ ['724', '31' ], # OI Brasil
40
+ ],
41
+
42
+ 'X-Up-Ch-Msisdn' => [
43
+ ['724', '06'], # Vivo Brasil
44
+ ['724', '10'], # Vivo Brasil
45
+ ['724', '11'], # Vivo Brasil
46
+ ['724', '23'], # Vivo Brasil
47
+ ],
48
+
49
+ 'X-Up-Subno' => [
50
+ ['732', '101'], # Claro Colombia and former Comcel Colombia
51
+ ['714', '03' ], # Claro Panamá
52
+ ],
53
+
54
+ 'X-Wap-Msisdn' => [
55
+ ['730', '03' ], # Claro Chile
56
+ ],
57
+
58
+ 'X-Wap-Sesiones3g-Mdn' => [
59
+ ['334', '040'], # Iusacell México
60
+ ['334', '050'], # Iusacell México
61
+ ],
62
+
63
+ 'X-Ztgo-Beareraddress' => [
64
+ ['740', '00'], # Movistar Ecuador
65
+ ],
66
+ }
67
+
68
+ end
@@ -0,0 +1,166 @@
1
+ require 'mobile_subscriber/http/known_imsi_headers'
2
+ require 'mobile_subscriber/http/known_msisdn_headers'
3
+
4
+ module MobileSubscriber::HTTP
5
+
6
+ class RequestInfo
7
+
8
+ attr_reader :remote_ip, :headers,
9
+ :imsi, :detected_imsi_header_name,
10
+ :msisdn, :detected_msisdn_header_name,
11
+ :mcc, :mnc
12
+
13
+ def initialize(env)
14
+
15
+ @remote_ip = env['REMOTE_ADDR']
16
+
17
+ # Reference Links:
18
+ # - http://www.slideshare.net/DefCamp/mobile-networks-exploiting-http-headers-and-data-traffic
19
+ # - http://www.mulliner.org/collin/academic/publications/mobile_web_privacy_icin10_mulliner.pdf
20
+ @headers = [
21
+ # HTTP Headers that contain important request details for validation
22
+ 'Max-Forwards', # Para validar el número de forwards que el cliente permite... muy pobre..
23
+ 'Via',
24
+ 'X-Forwarded-For', # lista de IP's que originaron la petición, en caso de pasar por proxies:
25
+
26
+ # HTTP headers that contain the MSISDN:
27
+ # http://www.mulliner.org/collin/academic/publications/mobile_web_privacy_icin10_mulliner.pdf
28
+ 'Cookie',
29
+ 'Igcli',
30
+ 'Msisdn',
31
+ 'Rapmin',
32
+ 'X-Cisco-Msisdn',
33
+ 'X-Cisco-Imsi',
34
+ 'X-Fh-Msisdn',
35
+ "X-H3-G-Msisdn",
36
+ 'X-Hts-Clid',
37
+ 'X-Imsi',
38
+ 'X-Jinny-Cid',
39
+ 'X-Msisdn',
40
+ 'X-Msp-Clid',
41
+ 'X-Msp-Msisdn',
42
+ 'X-Network-Info',
43
+ 'X-Nokia-Imsi', # This is a VERY useful one... if you have it!
44
+ 'X-Nokia-Msisdn',
45
+ 'X-Nx-Clid',
46
+ 'X-Orange-Cli',
47
+ 'X-Up-Calling-Line',
48
+ 'X-Up-Calling-Line-Id', # Not in referenced literature
49
+ 'X-Up-Ch-Msisdn', # Not in referenced literature
50
+ 'X-Up-Lsid',
51
+ 'X-Up-Subno', # Not in referenced literature
52
+ 'X-Wap-Fh-Subscriber-Info',
53
+ 'X-Wap-Msisdn',
54
+ 'X-Wap-Sesiones3g-Mdn', # Not in referenced literature
55
+ 'X-Wsb-Cli',
56
+ 'X-Ztgo-Beareraddress', # Not in referenced literature
57
+
58
+ # Headers that contain bearer information:
59
+ # http://www.mulliner.org/collin/academic/publications/mobile_web_privacy_icin10_mulliner.pdf
60
+ 'Bearer',
61
+ 'Bearer-Indication',
62
+ 'New-Bearer-Header',
63
+ 'Nokia-Bearer',
64
+ 'X-Nokia-Bearer',
65
+ 'X-Nokia-Musicshop-Bearer',
66
+ 'X-Up-Bear-Type', # NOT A TYPO
67
+ 'X-Up-Bearer-Type',
68
+ 'X-Bearer-Type',
69
+
70
+ # Headers that contain roaming information:
71
+ # http://www.mulliner.org/collin/academic/publications/mobile_web_privacy_icin10_mulliner.pdf
72
+ 'X-Orange-Roaming',
73
+ 'X-Nokia-Roaming',
74
+ 'X-Roaming',
75
+ 'X-Sdp-Roaming'
76
+ ].inject({}.with_indifferent_access) do |collected_headers, header_name|
77
+ header_env_key = "HTTP_#{header_name.split('-').map(&:upcase).join('_')}"
78
+
79
+ if env.has_key? header_env_key
80
+ collected_headers[header_name] = env[header_env_key].strip
81
+ end
82
+
83
+ collected_headers
84
+ end
85
+
86
+ # IMSI Extraction:
87
+ # Extract the first IMSI Header Value:
88
+ @imsi, @detected_imsi_header_name = MobileSubscriber::HTTP::KNOWN_IMSI_HEADER_MCC_MNC.inject([nil,nil]) do |result, keyval|
89
+ header_name = keyval[0]
90
+ if result.compact.blank? and current_imsi = headers[header_name]
91
+ result = [current_imsi, header_name] if current_imsi.length >= 14
92
+ end
93
+ result
94
+ end
95
+
96
+ # MSISDN Extraction:
97
+ # Extract the first MSISDN Header Value:
98
+ @msisdn, @detected_msisdn_header_name = MobileSubscriber::HTTP::KNOWN_MSISDN_HEADER_MCC_MNC.inject([nil,nil]) do |result, keyval|
99
+ header_name = keyval[0]
100
+ if result.compact.blank? and current_msisdn = headers[header_name]
101
+ result = [current_msisdn, header_name] if current_msisdn.length >= 8
102
+ end
103
+ result
104
+ end
105
+
106
+ # Mobile Operator Info Extraction:
107
+ extract_mobile_operator_info!
108
+
109
+ end
110
+
111
+ def has_imsi?
112
+ imsi.present?
113
+ end
114
+
115
+ def has_msisdn?
116
+ msisdn.present?
117
+ end
118
+
119
+ private
120
+
121
+ def extract_mobile_operator_info!
122
+
123
+ tuples_by_imsi = if has_imsi?
124
+ MobileSubscriber::HTTP::KNOWN_IMSI_HEADER_MCC_MNC[detected_imsi_header_name]
125
+ end
126
+
127
+ tuples_by_msisdn = if has_msisdn?
128
+ MobileSubscriber::HTTP::KNOWN_MSISDN_HEADER_MCC_MNC[detected_msisdn_header_name]
129
+ end
130
+
131
+ tuples_to_check = if tuples_by_imsi.present? && tuples_by_msisdn.present?
132
+ # Intersect known data from request - less tuples to check later
133
+ tuples_by_imsi & tuples_by_msisdn
134
+ elsif tuples_by_imsi.present?
135
+ tuples_by_imsi
136
+ elsif tuples_by_msisdn.present?
137
+ tuples_by_msisdn
138
+ end
139
+
140
+ detected_mobile_operator_info = if tuples_to_check.present? && tuples_to_check.any?
141
+ if has_imsi?
142
+ tuples_to_check.detect { |tuple| imsi.start_with?(tuple.join) }
143
+ elsif has_msisdn?
144
+
145
+ msisdn_country_code = (1..4).to_a.reverse.inject(nil) do |code, prefix_length|
146
+ current_prefix = msisdn[0,prefix_length]
147
+ if code.nil?
148
+ code = MobileSubscriber::DIALING_COUNTRY_CODES[current_prefix]
149
+ end
150
+ code
151
+ end
152
+
153
+ msisdn_mcc = MobileSubscriber::MCC_ISO_COUNTRY_CODES.detect { |key, val| val == msisdn_country_code }.first
154
+
155
+ # TODO Check for duplicates!
156
+ tuples_to_check.detect { |tuple| tuple.first == msisdn_mcc }
157
+
158
+ end
159
+ end
160
+
161
+ @mcc, @mnc = detected_mobile_operator_info if detected_mobile_operator_info.present?
162
+
163
+ end
164
+
165
+ end
166
+ end
@@ -1 +1,97 @@
1
- # Placeholder for the new Mobile User class
1
+ require 'mobile_subscriber/dictionaries/mobile_and_iso_country_codes'
2
+ require 'mobile_subscriber/dictionaries/dialing_and_country_codes'
3
+ require 'mobile_subscriber/dictionaries/operator_data'
4
+
5
+ module MobileSubscriber
6
+
7
+ # Identity class
8
+ class Identity
9
+
10
+ attr_reader :mcc, :mnc, :msisdn, :imsi, :http_request_info
11
+
12
+ alias_method :mobile_country_code, :mcc
13
+ alias_method :mobile_network_code, :mnc
14
+ alias_method :international_mobile_subscriber_identity, :imsi
15
+ alias_method :mobile_station_international_subscriber_directory_number, :msisdn
16
+
17
+ def initialize(attributes={})
18
+ @msisdn = attributes.delete :msisdn
19
+ @imsi = attributes.delete :imsi
20
+ @mcc = attributes.delete :mcc
21
+ @mnc = attributes.delete :mnc
22
+ @http_request_info = attributes.delete :http_request_info
23
+ end
24
+
25
+ def id
26
+ if imsi.present?
27
+ "imsi:#{imsi}"
28
+ else
29
+ "msisdn:#{msisdn}"
30
+ end
31
+ end
32
+ alias_method :to_s, :id
33
+
34
+ def dialing_code
35
+ if mcc.present?
36
+ dialing_codes = MobileSubscriber::DIALING_COUNTRY_CODES.select do |k,v|
37
+ v == iso_3166_country_code
38
+ end.keys
39
+
40
+ if msisdn.present?
41
+ max_length = dialing_codes.map(&:length).max
42
+ msisdn[0,max_length]
43
+ else
44
+ dialing_codes.first
45
+ end
46
+ end
47
+ end
48
+ alias_method :country_dialing_code, :dialing_code
49
+
50
+ def iso_3166_country_code
51
+ MobileSubscriber::MCC_ISO_COUNTRY_CODES[mcc] if mcc.present?
52
+ end
53
+
54
+ def mobile_network_brand
55
+ MobileSubscriber::OPERATOR_DATA[[mcc, mnc]][:brand] if mcc.present? && mnc.present?
56
+ end
57
+
58
+ def mobile_network_operator
59
+ MobileSubscriber::OPERATOR_DATA[[mcc, mnc]][:operator] if mcc.present? && mnc.present?
60
+ end
61
+
62
+ def inspect
63
+ "<MobileSubscriber::Identity #{self.id} (#{self.http_validated? ? '' : 'not '}validated by HTTP)>"
64
+ end
65
+
66
+ def http_validated?
67
+ @http_validated ||= false
68
+ end
69
+
70
+ # Creates a new MobileSubscriber::ISDN from a Rack::Request object
71
+ def self.new_from_request(request)
72
+ http_request_info = MobileSubscriber::HTTP::RequestInfo.new request.env
73
+
74
+ # TODO: Validate request for forged data HERE
75
+
76
+ if http_request_info.has_imsi? || http_request_info.has_msisdn?
77
+ validated_identity = new(
78
+ msisdn: http_request_info.msisdn,
79
+ imsi: http_request_info.imsi,
80
+ mcc: http_request_info.mcc,
81
+ mnc: http_request_info.mnc,
82
+ http_request_info: http_request_info
83
+ )
84
+ validated_identity.send :http_validated!
85
+ validated_identity
86
+ end
87
+ end
88
+
89
+ protected
90
+
91
+ def http_validated!
92
+ @http_validated = true
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -1,3 +1,3 @@
1
1
  module MobileSubscriber
2
- VERSION = "1.0.0.alpha4"
2
+ VERSION = "1.0.0.alpha5"
3
3
  end
@@ -96,4 +96,45 @@ class MobileSubscriber < Thor
96
96
 
97
97
  end
98
98
 
99
+ # Scrapes the Wikipedia entry of 'Mobile country code' to generate the dictionaries.
100
+ desc "update_country_dialing_codes", "Update the country dialing codes dictionary from countrycode.org"
101
+ def update_country_dialing_codes()
102
+
103
+ # Get the Wikipedia HTML and parse HTML with nokogiri:
104
+ page = Nokogiri::HTML(open "http://countrycode.org/")
105
+
106
+ funky_stripper = -> (str, pttrn) { str.chars.select { |c| c =~ pttrn }.join }
107
+
108
+ # Iterate over the main table > tbody > tr:
109
+ @country_code_data = page.css('table#main_table_blue > tbody > tr').inject([]) do |list, t_row|
110
+ t_cells = t_row.css('td')
111
+
112
+ # Capture the country name:
113
+ name = t_cells[0].text.strip
114
+
115
+ # Capture the iso codes:
116
+ # WTF strip does not work here to clear spaces!
117
+ alpha_2, alpha_3 = t_cells[1].text.split('/').map { |str| funky_stripper.call(str, /[A-Z]/) }
118
+
119
+ # Capture the dialing code:
120
+ dialing = funky_stripper.call(t_cells[2].text, /\d/)
121
+
122
+ # Add to list if alpha_2 and dialing code are both present:
123
+ if alpha_2.present? && dialing.present?
124
+ list << {
125
+ country_name: name,
126
+ iso_code_2: alpha_2,
127
+ iso_code_3: alpha_3,
128
+ dialing_code: dialing
129
+ }
130
+ end
131
+
132
+ # Return updated list:
133
+ list
134
+ end
135
+
136
+ template 'templates/dialing_and_country_codes.rb.erb', 'lib/mobile_subscriber/dictionaries/dialing_and_country_codes.rb'
137
+
138
+ end
139
+
99
140
  end
@@ -0,0 +1,28 @@
1
+ # Read about factories at https://github.com/thoughtbot/factory_girl
2
+
3
+ FactoryGirl.define do
4
+
5
+ factory :common_mobile_request_env, class: Hash do
6
+ initialize_with do
7
+ {
8
+ "HTTP_HOST" => "www.example.com",
9
+ "HTTP_CONNECTION" => "close",
10
+ "HTTP_CACHE_CONTROL" => "no-cache, max-age=0",
11
+ "HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
12
+ "HTTP_USER_AGENT" => "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
13
+ "HTTP_ACCEPT_ENCODING" => "gzip, deflate, sdch",
14
+ "HTTP_ACCEPT_LANGUAGE" => "en-US,en;q=0.8,es;q=0.6",
15
+ "HTTP_VERSION" => "HTTP/1.1"
16
+ }
17
+ end
18
+ end
19
+
20
+ factory :mobile_request, class: Rack::Request do
21
+ initialize_with do
22
+ new build(:common_mobile_request_env).merge(
23
+ "REMOTE_ADDR" => "201.144.162.4"
24
+ )
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,257 @@
1
+ # Read about factories at https://github.com/thoughtbot/factory_girl
2
+
3
+ FactoryGirl.define do
4
+
5
+ # Real request captured on claroapps.com at 2015-03-13
6
+ factory :mobile_request_from_claro_argentina, parent: :mobile_request do
7
+ initialize_with do
8
+ new build(:common_mobile_request_env).merge(
9
+ "REMOTE_ADDR" => "23.15.7.188",
10
+ "HTTP_ACCEPT" => "multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*",
11
+ "HTTP_ACCEPT_CHARSET"=> "utf-8,utf-16,iso-8859-1,iso-10646-ucs-2,Shift_JIS,Big5",
12
+ "HTTP_ACCEPT_ENCODING"=>"gzip",
13
+ "HTTP_ACCEPT_LANGUAGE"=>"es",
14
+ "HTTP_AKAMAI_ORIGIN_HOP"=>"1",
15
+ "HTTP_CACHE_CONTROL"=>"no-cache, max-age=0",
16
+ "HTTP_CONNECTION"=>"close",
17
+ "HTTP_CONNECT_TIME"=>"4",
18
+ "HTTP_COOKIE" => "request_method=GET; HttpOnly=; ",
19
+ "HTTP_COOKIE2"=>"$Version=1",
20
+ "HTTP_HOST"=>"www.claroapps.com",
21
+ "HTTP_PRAGMA"=>"no-cache",
22
+ "HTTP_TOTAL_ROUTE_TIME"=>"0",
23
+ "HTTP_USER_AGENT"=> "SonyEricssonW580i/R8BE Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1",
24
+ "HTTP_VERSION"=>"HTTP/1.1",
25
+ "HTTP_VIA"=>"1.1 akamai.net(ghost) (AkamaiGHost), 1.1 vegur",
26
+ "HTTP_X_AKAMAI_CONFIG_LOG_DETAIL"=>"true",
27
+ "HTTP_X_FORWARDED_FOR"=>"172.65.159.141, 170.51.255.15, 23.15.7.188",
28
+ "HTTP_X_FORWARDED_PORT"=>"80",
29
+ "HTTP_X_FORWARDED_PROTO"=>"http",
30
+ "HTTP_X_NOKIA_BEARER"=>"CSD or GPRS or 3G",
31
+ "HTTP_X_NOKIA_CHARGINGID"=>"-335177295",
32
+ "HTTP_X_NOKIA_GATEWAY"=>"NBG/4.0/1",
33
+ "HTTP_X_NOKIA_GGSNIPADDRESS"=>"170.51.252.245",
34
+ "HTTP_X_NOKIA_IMSI"=>"722310115238848",
35
+ "HTTP_X_NOKIA_IPADDRESS"=>"172.65.159.141",
36
+ "HTTP_X_NOKIA_LOCALSOCKET"=>"192.168.16.239:8080",
37
+ "HTTP_X_NOKIA_MAXDOWNLINKBITRATE"=>"0",
38
+ "HTTP_X_NOKIA_MAXUPLINKBITRATE"=>"0",
39
+ "HTTP_X_NOKIA_MSISDN"=>"5491126368595",
40
+ "HTTP_X_NOKIA_PREPAIDID"=>"4",
41
+ "HTTP_X_NOKIA_REMOTESOCKET"=>"172.65.159.141:16513",
42
+ "HTTP_X_NOKIA_ROAMINGID"=>"1",
43
+ "HTTP_X_NOKIA_SGSNIPADDRESS"=>"186.158.128.49",
44
+ "HTTP_X_REQUEST"=>"3e0f82f8-b086-4ad2-8793-c60e6a94c443",
45
+ "HTTP_X_REQUEST_START"=>"1426256922162",
46
+ "HTTP_X_WAP_PROFILE"=>"\"http://wap.sonyericsson.com/UAprof/W580iR201.xml\""
47
+ )
48
+ end
49
+ end
50
+
51
+ factory :mobile_request_from_claro_brasil, parent: :mobile_request do
52
+ initialize_with do
53
+ new build(:common_mobile_request_env).merge(
54
+ "REMOTE_ADDR" => "201.23.176.202",
55
+ "HTTP_MSISDN" => "5500000000000"
56
+ )
57
+ end
58
+ end
59
+
60
+ # TODO: Replace with a real example:
61
+ factory :mobile_request_from_claro_dominican_republic, parent: :mobile_request do
62
+ initialize_with do
63
+ new build(:common_mobile_request_env).merge(
64
+ "REMOTE_ADDR" => "181.37.104.3",
65
+ "HTTP_MSISDN" => "18098591800"
66
+ )
67
+ end
68
+ end
69
+
70
+ # http://ns.myip.ms/view/ip_owners/181034/Claro_Chile_S_a.html
71
+ factory :mobile_request_from_claro_chile, parent: :mobile_request do
72
+ initialize_with do
73
+ new build(:common_mobile_request_env).merge(
74
+ "REMOTE_ADDR" => "191.116.39.114",
75
+ "HTTP_X_WAP_MSISDN" => "56024440000"
76
+ )
77
+ end
78
+ end
79
+
80
+ factory :mobile_request_from_claro_colombia, parent: :mobile_request do
81
+ initialize_with do
82
+ new build(:common_mobile_request_env).merge(
83
+ "REMOTE_ADDR" => "200.26.137.100",
84
+ "HTTP_X_UP_SUBNO" => "57000000000"
85
+ )
86
+ end
87
+ end
88
+
89
+ # TODO: Replace with a real example request:
90
+ factory :mobile_request_from_claro_costa_rica, parent: :mobile_request do
91
+ initialize_with do
92
+ new build(:common_mobile_request_env).merge(
93
+ "REMOTE_ADDR" => "186.26.126.37",
94
+ "HTTP_X_NOKIA_MSISDN" => "50600000000"
95
+ )
96
+ end
97
+ end
98
+
99
+ # Real request taken on 2015-04-09 16:07:05
100
+ factory :mobile_request_from_claro_puerto_rico, parent: :mobile_request do
101
+ initialize_with do
102
+ new build(:common_mobile_request_env).merge(
103
+ "REMOTE_ADDR" => "63.235.37.23",
104
+ "HTTP_ACCEPT" => "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
105
+ "HTTP_ACCEPT_CHARSET" =>"utf-8, iso-8859-1, utf-16, *;q=0.7",
106
+ "HTTP_ACCEPT_ENCODING" =>"gzip",
107
+ "HTTP_ACCEPT_LANGUAGE" =>"en-US",
108
+ "HTTP_AKAMAI_ORIGIN_HOP" =>"1",
109
+ "HTTP_CACHE_CONTROL" =>"no-cache, max-age=0",
110
+ "HTTP_CONNECT_TIME" =>"0",
111
+ "HTTP_CONNECTION" =>"close",
112
+ "HTTP_HOST" =>"api.claroapps.com",
113
+ "HTTP_PRAGMA" =>"no-cache",
114
+ "HTTP_TOTAL_ROUTE_TIME" =>"0",
115
+ "HTTP_USER_AGENT" => "Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; GT-I9070 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
116
+ "HTTP_VERSION" =>"HTTP/1.1",
117
+ "HTTP_VIA" =>"1.1 akamai.net(ghost) (AkamaiGHost), 1.1 vegur",
118
+
119
+ "HTTP_X_AKAMAI_CONFIG_LOG_DETAIL" =>"true",
120
+
121
+ "HTTP_X_CISCO_IMSI" =>"330110010202360",
122
+ "HTTP_X_CISCO_MSISDN" =>"17873131471",
123
+
124
+ "HTTP_X_FORWARDED_FOR" =>"63.135.255.59, 63.235.37.23",
125
+ "HTTP_X_FORWARDED_PORT" =>"80",
126
+ "HTTP_X_FORWARDED_PROTO" =>"http",
127
+
128
+ "HTTP_X_REQUEST_ID" =>"4b67a488-619e-4366-9437-f5e5e746f971",
129
+ "HTTP_X_REQUEST_START" =>"1428595625229",
130
+ "HTTP_X_WAP_PROFILE" =>"http://wap.samsungmobile.com/uaprof/GT-I9070.xml"
131
+ )
132
+ end
133
+ end
134
+
135
+ # http://myip.ms/view/ip_owners/80612/Conecel.html
136
+ factory :mobile_request_from_claro_ecuador, parent: :mobile_request do
137
+ initialize_with do
138
+ new build(:common_mobile_request_env).merge(
139
+ "REMOTE_ADDR" => "190.63.1.10",
140
+ "HTTP_MSISDN" => "59342690000"
141
+ )
142
+ end
143
+ end
144
+
145
+ # Request from a client through Claro Guatemala network:
146
+ # (Built from an actual ATP test)
147
+ factory :mobile_request_from_claro_guatemala, parent: :mobile_request do
148
+ initialize_with do
149
+ new build(:common_mobile_request_env).merge(
150
+ "REMOTE_ADDR" => "216.230.152.158",
151
+ "HTTP_X_NOKIA_MSISDN" => "50241865146",
152
+ "HTTP_X_NOKIA_IMSI" => "704012013128442",
153
+ "HTTP_X_FORWARDED_FOR" => "190.212.233.218, 204.0.3.199"
154
+ )
155
+ end
156
+ end
157
+
158
+ # TODO: Replace with a real example:
159
+ factory :mobile_request_from_claro_honduras, parent: :mobile_request do
160
+ initialize_with do
161
+ new build(:common_mobile_request_env).merge(
162
+ "REMOTE_ADDR" => "190.107.157.31",
163
+ "HTTP_X_NOKIA_MSISDN" => "50430000000"
164
+ )
165
+ end
166
+ end
167
+
168
+ # TODO: Replace with a real example request:
169
+ factory :mobile_request_from_claro_nicaragua, parent: :mobile_request do
170
+ initialize_with do
171
+ new build(:common_mobile_request_env).merge(
172
+ "REMOTE_ADDR" => "190.212.88.8",
173
+ "HTTP_X_NOKIA_MSISDN" => "50500000000"
174
+ )
175
+ end
176
+ end
177
+
178
+ # TODO: Replace with a real example request:
179
+ factory :mobile_request_from_claro_el_salvador, parent: :mobile_request do
180
+ initialize_with do
181
+ new build(:common_mobile_request_env).merge(
182
+ "REMOTE_ADDR" => "190.86.139.225",
183
+ "HTTP_X_NOKIA_MSISDN" => "50300000000"
184
+ )
185
+ end
186
+ end
187
+
188
+ # Real request recorded at claroapps.com at 2015-03-24
189
+ factory :mobile_request_from_claro_peru, parent: :mobile_request do
190
+ initialize_with do
191
+ new build(:common_mobile_request_env).merge(
192
+ "REMOTE_ADDR" => "216.246.75.208", # This IP belongs to a U.S. datacenter which acts as proxy for the real user...
193
+
194
+ "HTTP_ACCEPT_LANGUAGE" => "es-PE,es-419;q=0.8,es;q=0.6",
195
+ "HTTP_AKAMAI_ORIGIN_HOP" => "1",
196
+ "HTTP_CONNECT_TIME" => "3",
197
+ "HTTP_PRAGMA" => "no-cache",
198
+ "HTTP_TOTAL_ROUTE_TIME" => "5",
199
+ "HTTP_VERSION" => "HTTP/1.1",
200
+ "HTTP_VIA" => "1.1 akamai.net(ghost) (AkamaiGHost), 1.1 vegur",
201
+
202
+ # X Headers:
203
+ "HTTP_X_AKAMAI_CONFIG_LOG_DETAIL" => "true",
204
+
205
+ # The leftmost IP is the:
206
+ # - Closer to the User (or the actual user IP)
207
+ # - Less trustable
208
+ "HTTP_X_FORWARDED_FOR" => "190.113.210.147, 216.246.75.208",
209
+ "HTTP_X_NOKIA_IMSI" => "716100316259449",
210
+ "HTTP_X_REQUEST" => "272aa345-55cc-45b2-b879-79678957817f",
211
+
212
+ "HTTP_X_REQUEST_START" => "1427225820026",
213
+ "HTTP_X_FORWARDED_PORT" => "80",
214
+ "HTTP_X_FORWARDED_PROTO" => "http",
215
+ "HTTP_X_UP_CALLING_LINE_ID" => "51941037249"
216
+ )
217
+ end
218
+ end
219
+
220
+ # Real request sample captured at claroapps.com on 2015-03-13
221
+ factory :mobile_request_from_claro_panama, parent: :mobile_request do
222
+ initialize_with do
223
+ new build(:common_mobile_request_env).merge(
224
+ "REMOTE_ADDR" => "216.246.75.196",
225
+
226
+ # Client generated headers:
227
+ "HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
228
+ "HTTP_ACCEPT_ENCODING" => "gzip",
229
+ "HTTP_ACCEPT_LANGUAGE" => "es-es",
230
+ "HTTP_CONNECTION" => "close",
231
+ "HTTP_HOST" => "api.claroapps.com",
232
+ "HTTP_PRAGMA" => "no-cache",
233
+ "HTTP_USER_AGENT" => "Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B466 Safari/600.1.4",
234
+ "HTTP_VERSION" => "HTTP/1.1",
235
+
236
+ # Mobile Network generated headers:
237
+ "HTTP_X_APN" => "web.claro.com.pa",
238
+ "HTTP_X_IMSI" => "714030003647380",
239
+ "HTTP_X_UP_SUBNO" => "50762526353",
240
+
241
+ # Akamai generated/modified headers:
242
+ "HTTP_AKAMAI_ORIGIN_HOP" => "1",
243
+ "HTTP_CONNECT_TIME" => "1",
244
+ "HTTP_CACHE_CONTROL" => "no-cache, max-age=0",
245
+ "HTTP_X_AKAMAI_CONFIG_LOG_DETAIL" => "true",
246
+ "HTTP_TOTAL_ROUTE_TIME" => "0",
247
+ "HTTP_VIA" => "1.1 akamai.net(ghost) (AkamaiGHost), 1.1 vegur",
248
+ "HTTP_X_FORWARDED_FOR" => "181.179.0.28, 216.246.75.196",
249
+ "HTTP_X_FORWARDED_PORT" => "80",
250
+ "HTTP_X_FORWARDED_PROTO" => "http",
251
+ "HTTP_X_REQUEST" => "d141e3e0-0282-4f44-9e45-470a834976a1",
252
+ "HTTP_X_REQUEST_START" => "1426248962827"
253
+ )
254
+ end
255
+ end
256
+
257
+ end