ige_isb_api 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,249 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ require "net/http"
5
+ require "uri"
6
+ require 'cgi'
7
+ require 'date'
8
+ require "ige_isb_api"
9
+ require "ige_isb_api/constants"
10
+
11
+ module IGE_ISB_API
12
+ class Bonus
13
+ attr_accessor :command, :params, :request
14
+
15
+ DEFAULT_PARAMS = {
16
+ 'api_key' => IGE_ISB_API::Constants::BONUS_API_KEY
17
+ }
18
+
19
+ COMMON_FIELDS = {
20
+ 'api_key' => {:required => true, :type => 'string', :length => 128}
21
+ }
22
+
23
+ COMMANDS = {
24
+ 'get_trigger_bonus' => {
25
+ 'login' => {:required => true, :type => 'username', :length => 32},
26
+ 'trigger' => {required: true, type: 'string', values: ['sign up', 'deposit', 'promotion code']},
27
+ 'transaction_ref' => {required: false, type: 'string', length: 128}
28
+ },
29
+ 'get_client_bonuses' => {
30
+ 'login' => {:required => true, :type => 'username', :length => 32},
31
+ 'statuses' => {required: false, type: 'string',
32
+ values: IGE_ISB_API::Constants::ALLOWED_BONUS_STATUSES},
33
+ 'types' => {required: false, type: 'string',
34
+ values: IGE_ISB_API::Constants::ALLOWED_BONUS_TYPES},
35
+ 'cartecs' => {required: false, type: 'string', length: 255},
36
+ 'start_date' => {required: false, type: 'date'},
37
+ 'end_date' => {required: false, type: 'date'},
38
+ 'start' => {required: false, type: 'int'},
39
+ 'results_per_page' => {required: false, type: 'int'},
40
+ 'order_by_field' => {required: false, type: 'string', values: [
41
+ 'cartec', 'bonus_initial_value', 'bonus_current_value', 'bonus_state',
42
+ 'bonus_type', 'issue_date', 'expiration_date', 'bonus_finish_date',
43
+ 'issued_by', 'total_bet', 'name'
44
+ ]},
45
+ 'order_by_dir' => {required: false, type: 'string', values: ['ASC', 'DESC']},
46
+ 'include_expired' => {required: false, type: 'boolint'},
47
+ 'only_expired' => {required: false, type: 'boolint'}
48
+ },
49
+ 'count_client_bonuses' => {
50
+ 'login' => {required: true, type: 'username'},
51
+ 'statuses' => {required: false, type: 'string',
52
+ values: IGE_ISB_API::Constants::ALLOWED_BONUS_STATUSES},
53
+ 'types' => {required: false, type: 'string',
54
+ values: IGE_ISB_API::Constants::ALLOWED_BONUS_TYPES},
55
+ 'cartecs' => {required: false, type: 'string', length: 255},
56
+ 'start_date' => {required: false, type: 'date'},
57
+ 'end_date' => {required: false, type: 'date'},
58
+ 'include_expired' => {required: false, type: 'boolint'},
59
+ 'only_expired' => {required: false, type: 'boolint'}
60
+ },
61
+ 'has_pending_offers' => {
62
+ 'login' => {required: true, type: 'username'},
63
+ },
64
+ 'accept_bonus' => {
65
+ 'login' => {required: true, type: 'username'},
66
+ 'id' => {required: true, type: 'int'}
67
+ },
68
+ 'decline_bonus' => {
69
+ 'login' => {required: true, type: 'username'},
70
+ 'id' => {required: true, type: 'int'}
71
+ },
72
+ 'get_remaining_playthrough' => {
73
+ 'login' => {required: true, type: 'username'}
74
+ },
75
+ 'remove_bonus_and_winnings_on_withdraw' => {
76
+ 'login' => {required: true, type: 'username'}
77
+ },
78
+ 'issue_bonus' => {
79
+ 'login' => {required: true, type: 'username'},
80
+ 'id_template' => {required: false, type: 'int'},
81
+ 'amount' => {required: false, type: 'currency'},
82
+ 'deposit_number' => {required: false, type: 'int'},
83
+ 'transaction_ref' => {required: false, type: 'string'},
84
+ 'transaction_type' => {required: false, type: 'string'},
85
+ 'transaction_date' => {required: false, type: 'timestamp'},
86
+ 'promo' => {required: false, type: 'string'},
87
+ 'location' => {required: false, type: 'string', values: ['cert', 'certd']}
88
+ },
89
+ 'cancel_bonus' => {
90
+ 'login' => {required: true, type: 'username'},
91
+ 'id_template' => {required: false, type: 'int'},
92
+ 'comment' => {required: false, type: 'string'}
93
+ },
94
+ 'reset_bonus' => {
95
+ 'login' => {required: true, type: 'username'}
96
+ },
97
+ 'update_active_balance_current_value' => {
98
+ 'login' => {required: true, type: 'username'},
99
+ 'deposit' => {required: true, type: 'currency'}
100
+ },
101
+ 'assign_certificate_to_player' => {
102
+ 'email' => {required: true, type: 'email', length: 50},
103
+ 'certificate_name' => {required: true, type: 'string'}
104
+ },
105
+ 'bonus_vip_points' => {
106
+ 'login' => {required: true, type: 'username'},
107
+ 'amount' => {required: true, type: 'currency'},
108
+ 'reason' => {required: false, type: 'string'},
109
+ 'name' => {required: true, type: 'string'}
110
+ },
111
+ 'generate_certificate' => {
112
+ 'template_certificate_id' => {required: true, type: 'int'}
113
+ },
114
+ 'generate_player_assigned_certificate' => {
115
+ 'login' => {required: true, type: 'username'},
116
+ 'template_certificate_id' => {required: true, type: 'int'}
117
+ },
118
+ 'get_template_id_by_name' => {
119
+ 'name' => {required: true, type: 'string'}
120
+ },
121
+ 'count_promo_codes' => {
122
+ 'login' => {required: true, type: 'username'},
123
+ 'start_date' => {required: true, type: 'timestamp'},
124
+ 'end_date' => {required: true, type: 'timestamp'}
125
+ },
126
+ 'sum_bonuses' => {
127
+ 'login' => {required: true, type: 'username'},
128
+ 'casino_prefix' => {required: false, type: 'string'}
129
+ },
130
+ 'is_transaction_used' => {
131
+ 'login' => {required: true, type: 'username'},
132
+ 'transaction' => {required: true, type: 'string'}
133
+ },
134
+ 'get_player_assigned_certificates' => {
135
+ 'login' => {required: true, type: 'username'},
136
+ 'promotion_code' => {required: false, type: 'string'},
137
+ 'template_certificate_ids' => {required: false, type: 'string'},
138
+ 'start_date' => {required: false, type: 'date'},
139
+ 'end_date' => {required: false, type: 'date'}
140
+ },
141
+ 'delete_player_assigned_certificate' => {
142
+ 'login' => {required: true, type: 'username'},
143
+ 'promotion_code' => {required: true, type: 'string'}
144
+ },
145
+ 'delete_generated_certificate' => {
146
+ 'promotion_code' => {required: true, type: 'string'}
147
+ },
148
+ 'certificate_exists' => {
149
+ 'promotion_code' => {required: true, type: 'string'}
150
+ }
151
+ }
152
+
153
+ def initialize(command, params = {})
154
+ self.command = command
155
+ self.params = self.class::DEFAULT_PARAMS.merge(self.convert_symbols_to_strings(params))
156
+ self.validate_parameters
157
+ # a bunch of stuff
158
+ self.sign
159
+ self.construct_request
160
+ end
161
+
162
+ def send
163
+ uri = URI.parse(IGE_ISB_API::Constants::BONUS_API_SERVER)
164
+ http = Net::HTTP.new(uri.host, uri.port)
165
+ # see http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
166
+ # http.use_ssl = true
167
+ # http.cert = OpenSSL::X509::Certificate.new(pem)
168
+ # http.key = OpenSSL::PKey::RSA.new(pem)
169
+ # http.verify_mode = OpenSSL::SSL::VERIFY_PEER
170
+ return http.request(self.request)
171
+ end
172
+
173
+ protected
174
+
175
+ # hash generated through the HMAC method using the sha256 algorithm with a private md5 key provided by ISB.
176
+ # The hash has to be made up of the url encoded query string, excluding the api_key
177
+ # Example: hash_hmac(“sha256”,urlencode(“param1=value1&param2=value2&param3=value3”),”private_key”)
178
+ def sign
179
+ return unless self.params['signature'].nil?
180
+ encoded_params = self.params.map { |key, value| "#{key}=#{value}" }
181
+ encoded_params.shift # remove the first item which is always the 'api_key'
182
+ hmac = Digest::HMAC.new(IGE_ISB_API::Constants::BONUS_SECRET_KEY, Digest::SHA256)
183
+ hmac << CGI.escape(encoded_params.join('&'))
184
+ self.params['signature'] = hmac.to_s
185
+ # puts "debugging params: api_key=#{self.params['api_key']}&#{encoded_params.join('&')}&signature=#{hmac.to_s}"
186
+ end
187
+
188
+ def convert_symbols_to_strings(a_hash = {})
189
+ return {} if a_hash.empty?
190
+ result = {}
191
+ a_hash.each {|key, value| result[key.to_s] = value }
192
+ return result
193
+ end
194
+
195
+ def validate_parameters
196
+ comfields = self.class::COMMANDS[self.command]
197
+ raise ValidationException, "Invalid command #{command}." if comfields.nil?
198
+ fields = self.class::COMMON_FIELDS.merge(comfields)
199
+ self.validate_fields(fields)
200
+ self.validate_no_extra_fields(fields)
201
+ end
202
+
203
+ def validate_fields(against)
204
+ against.each do |name, meta|
205
+ required = (meta[:required] === true)
206
+ # Check that all required parameters are present
207
+ if required && !self.params.keys.include?(name)
208
+ raise ValidationException, "Parameter #{name} is required, but missing from #{self.params.keys}"
209
+ end
210
+ if self.params.keys.include? name
211
+ p = self.params[name]
212
+ if p != nil
213
+ case meta[:type]
214
+ when 'timestamp'
215
+ self.params[name] = p = p.to_time.utc.to_i if p.is_a? Date
216
+ self.params[name] = p = p.utc.to_i if p.is_a?(Time)
217
+ self.params[name] = p = p.to_i if p.is_a?(String)
218
+ when 'currency'
219
+ p = p.to_f if p.is_a? String
220
+ if (p.is_a?(Float) || p.is_a?(Integer)) && p > 0
221
+ self.params[name] = p = "%.2f" % p
222
+ end
223
+ end
224
+ opts = {}
225
+ opts[:length] = meta[:length] if meta[:length]
226
+ opts[:values] = meta[:values] if meta[:values]
227
+ IGE_ISB_API::Validation.test name, self.params[name], meta[:type], opts
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ def validate_no_extra_fields(against)
234
+ allowed_fields = against.keys
235
+ self.params.each do |key, value|
236
+ raise InternalException, "Field #{key} is not supported" if !allowed_fields.include?(key)
237
+ end
238
+ end
239
+
240
+ def construct_request
241
+ raise RuntimeError, "Missing environment variable 'ISOFTBET_BONUS_API_SERVER'" if IGE_ISB_API::Constants::BONUS_API_SERVER.nil?
242
+ uri = URI.parse("#{IGE_ISB_API::Constants::BONUS_API_SERVER}/bonus_system/api/#{self.command}")
243
+ # http = Net::HTTP.new(uri.host, uri.port)
244
+ self.request = Net::HTTP::Post.new(uri)
245
+ self.request.set_form_data(self.params)
246
+ end
247
+
248
+ end
249
+ end
@@ -0,0 +1,125 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ module IGE_ISB_API
5
+ class BonusAPI
6
+
7
+ def initialize()
8
+ # nothing to do here right now.
9
+ end
10
+
11
+ # the following options *must* be passed in.
12
+ # trigger: one of 'sign up', 'deposit', or 'promotion code'
13
+ # login: "the user's username, as registered with ISB",
14
+ #
15
+ # The following may be passed in and are presented here with their defaults.
16
+ # transaction_ref: some unique transaction reference,
17
+ def get_trigger_bonus(opts = {})
18
+ return get_response_for __method__.to_s, opts
19
+ end
20
+
21
+ def get_client_bonuses(opts = {})
22
+ return get_response_for __method__.to_s, opts
23
+ end
24
+
25
+ def count_client_bonuses(opts = {})
26
+ return get_response_for __method__.to_s, opts
27
+ end
28
+
29
+ def has_pending_offers(opts = {})
30
+ return get_response_for __method__.to_s, opts
31
+ end
32
+
33
+ def accept_bonus(opts = {})
34
+ return get_response_for __method__.to_s, opts
35
+ end
36
+
37
+ def decline_bonus(opts = {})
38
+ return get_response_for __method__.to_s, opts
39
+ end
40
+
41
+ def get_remaining_playthrough(opts = {})
42
+ return get_response_for __method__.to_s, opts
43
+ end
44
+
45
+ def remove_bonus_and_winnings_on_withdraw(opts = {})
46
+ return get_response_for __method__.to_s, opts
47
+ end
48
+
49
+ def issue_bonus(opts = {})
50
+ return get_response_for __method__.to_s, opts
51
+ end
52
+
53
+ def cancel_bonus(opts = {})
54
+ return get_response_for __method__.to_s, opts
55
+ end
56
+
57
+ def reset_bonus(opts = {})
58
+ return get_response_for __method__.to_s, opts
59
+ end
60
+
61
+ def update_active_balance_current_value(opts = {})
62
+ return get_response_for __method__.to_s, opts
63
+ end
64
+
65
+ def assign_certificate_to_player(opts = {})
66
+ return get_response_for __method__.to_s, opts
67
+ end
68
+
69
+ def bonus_vip_points(opts = {})
70
+ return get_response_for __method__.to_s, opts
71
+ end
72
+
73
+ def generate_certificate(opts = {})
74
+ return get_response_for __method__.to_s, opts
75
+ end
76
+
77
+ def generate_player_assigned_certificate(opts = {})
78
+ return get_response_for __method__.to_s, opts
79
+ end
80
+
81
+ def get_template_id_by_name(opts = {})
82
+ return get_response_for __method__.to_s, opts
83
+ end
84
+
85
+ def count_promo_codes(opts = {})
86
+ return get_response_for __method__.to_s, opts
87
+ end
88
+
89
+ def sum_bonuses(opts = {})
90
+ return get_response_for __method__.to_s, opts
91
+ end
92
+
93
+ def is_transaction_used(opts = {})
94
+ return get_response_for __method__.to_s, opts
95
+ end
96
+
97
+ def get_player_assigned_certificates(opts = {})
98
+ return get_response_for __method__.to_s, opts
99
+ end
100
+
101
+ def delete_player_assigned_certificate(opts = {})
102
+ return get_response_for __method__.to_s, opts
103
+ end
104
+
105
+ def delete_generated_certificate(opts = {})
106
+ return get_response_for __method__.to_s, opts
107
+ end
108
+
109
+ def certificate_exists(opts = {})
110
+ return get_response_for __method__.to_s, opts
111
+ end
112
+
113
+ protected
114
+
115
+ def get_response_for(a_command, opts = {})
116
+ # puts "got command #{a_command} with options #{opts}"
117
+ raise ArgumentError, "Missing options." if opts.empty?
118
+ bonus_request = IGE_ISB_API::Bonus.new a_command, opts
119
+ resp = bonus_request.send
120
+ response = JSON.parse(resp.body)
121
+ return response
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,83 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+ require 'digest'
4
+
5
+ module IGE_ISB_API
6
+ class Callback
7
+
8
+ # {
9
+ # "player": String # player login as originally passed to ISB at .registration,
10
+ # "requestid":Integer, # same as we provided in the IDREQUEST field
11
+ # "token": String - # a SHA2 digest of our 'SECRETKEY' + 'IDREQUEST' which we will use to authenticate the incoming info.,
12
+ # "sesson-start":"2013/10/25.10:54:18",
13
+ # "sesson-end":"2013/10/25.12:32:51",
14
+ # "skin_ID": 2019
15
+ # "currency":"USD",
16
+ # "hostID":1,
17
+ # "actions":[
18
+ # {
19
+ # "bet":{
20
+ # "amount": 1.00
21
+ # },
22
+ # "bet":{
23
+ # "amount": 50.00
24
+ # },
25
+ # "win":{
26
+ # "amount": 80.00
27
+ # }
28
+ # }
29
+ # ]
30
+ # }
31
+ def self.parse(raw_data)
32
+ raise ValidationException, "No data to parse" if raw_data.nil? || raw_data.empty?
33
+ begin
34
+ data = JSON.parse(raw_data)
35
+ player = data['player']
36
+ IGE_ISB_API::Validation.test('player', player, 'username')
37
+ requestid = data['requestid'].to_i
38
+ IGE_ISB_API::Validation.test('requestid', requestid, 'int')
39
+ token = data['token']
40
+ expected = (Digest::SHA2.new << "#{IGE_ISB_API::Constants::SECRET_KEY}#{requestid}").to_s
41
+ raise ValidationException, "Invalid Token" unless token == expected
42
+ session_start = DateTime.strptime(data['session-start'], "%Y/%m/%d.%H:%M:%S").to_time.utc
43
+ session_end = DateTime.strptime(data['session-end'], "%Y/%m/%d.%H:%M:%S").to_time.utc
44
+ raise ValidationException, "session-end must be after session-start" unless session_start < session_end
45
+ skinid = data['skin_ID'].to_i
46
+ IGE_ISB_API::Validation.test('skin_ID', skinid, 'int')
47
+ currency = data['currency']
48
+ IGE_ISB_API::Validation.test('currency', currency, 'currency_code')
49
+ hostid = data['hostID'].to_i
50
+ actions = data['actions'].map do |act|
51
+ if act['bet']
52
+ {
53
+ action: :bet,
54
+ amount: act['bet']['amount'].to_f
55
+ }
56
+ elsif act['win']
57
+ {
58
+ action: :win,
59
+ amount: act['win']['amount'].to_f
60
+ }
61
+ else
62
+ raise ValidationException, "Invalid Action"
63
+ end
64
+ end
65
+ return {
66
+ player: player,
67
+ requestid: requestid,
68
+ session_start: session_start,
69
+ session_end: session_end,
70
+ skinid: skinid,
71
+ currency: currency,
72
+ hostid: hostid,
73
+ actions: actions
74
+ }
75
+ rescue ArgumentError => ae
76
+ raise ValidationException, ae.message
77
+ rescue JSON::ParserError => jpe
78
+ raise ValidationException, "Invalid JSON format in supplied data: #{jpe.message}"
79
+ end
80
+ end
81
+
82
+ end
83
+ end