scanpay 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6093d5e45c3d89d5d0a00932332b77480fc9302f
4
- data.tar.gz: 3816e82d5806ccf80cda78133eafb099e741a380
3
+ metadata.gz: 5ffa65f23cd1a8b6c6266024ba9d4b1f23c87c23
4
+ data.tar.gz: 15c61f463bbe53410e9ef42e055b854dbd9db854
5
5
  SHA512:
6
- metadata.gz: 8c6efd2da4e67b56d8b9cbbe412d1517d1a2c6faf2b5c93143a58b914158c616a91a0c3c6304b1d3827cbedb6a790303cf420590b6ea89937787d3bbfc022223
7
- data.tar.gz: 87d7e4fd38b66776004915cb3b7aa0cf77eb4a3399123b4cc332ade055c501c838daeb00808d34ef84b8377a9d679042224bb830320e4aaf7fabcfff866ddfcf
6
+ metadata.gz: 236a61508993ebfea15fda6c90b0b8b51b0236920d0e3e07ac048b4e26023a935b2196c89f8cf9834208a3e06c1b37104cf144a97690c2522ff66917d32bc203
7
+ data.tar.gz: f3218fdf758c3dfd77f10f653af61bffc310c1dae7eb82818d411f1f8a08ad7f99e3fab8ef2030d49a76cbc99d70bb99cf7c1d6277523e6651ba86151319f4d7
@@ -1,72 +1,83 @@
1
- require 'net/http'
1
+ # help@scanpay.dk || irc.scanpay.dk:6697 || scanpay.dk/slack
2
2
  require 'base64'
3
3
  require 'json'
4
4
  require 'openssl'
5
- require 'httpclient'
5
+ require 'httpclient' # Thread-Safe. Consider https://github.com/httprb/http
6
6
 
7
7
  module Scanpay
8
-
9
- class Error < Exception
10
- end
8
+ class Error < StandardError; end
11
9
 
12
10
  class Client
13
- @httpclient
11
+ @https
12
+ @headers
14
13
  @apikey
15
14
 
16
15
  def initialize(apikey)
17
- @httpclient = HTTPClient.new
18
- @httpclient.ssl_config.set_default_paths
16
+ @https = HTTPClient.new
17
+ @https.ssl_config.set_default_paths
18
+ @https.connect_timeout = 20 # seconds
19
19
  @apikey = apikey
20
+ @headers = {
21
+ 'authorization' => 'basic ' + Base64.strict_encode64(apikey),
22
+ 'x-sdk' => 'Ruby-1.0.0/' + RUBY_VERSION,
23
+ 'content-type' => 'application/json',
24
+ }
20
25
  end
21
26
 
22
- def consttime_streq(a, b)
27
+ def timesafe_equals(a, b)
23
28
  return false if a.bytesize != b.bytesize
24
29
  neq = 0
25
30
  a.bytes.each_index { |i|
26
31
  neq |= a.bytes[i] ^ b.bytes[i];
27
32
  }
28
- neq == 0
33
+ return neq === 0
29
34
  end
30
35
 
31
- def request(uri, data, opts)
32
- header = {
33
- 'Authorization' => 'Basic ' + Base64.strict_encode64(@apikey),
34
- 'X-Scanpay-SDK' => 'Ruby-1.0.0',
35
- 'Content-Type' => 'application/json',
36
- }
37
- res = nil
38
- if data == nil
39
- res = @httpclient.get('https://api.scanpay.dk/v1' + uri, nil, header)
40
- else
41
- res = @httpclient.post('https://api.scanpay.dk/v1' + uri, data.to_json, header)
36
+ def request(path, data, opts={})
37
+ hostname = opts['hostname'] || 'api.scanpay.dk'
38
+ headers = @headers.clone
39
+
40
+ # Let merchant override HTTP headers
41
+ if opts.has_key? 'headers'
42
+ opts['headers'].each do |key, value|
43
+ headers[key.downcase] = value
44
+ end
42
45
  end
43
- raise Error, 'Invalid API-key' if res.code == 403
44
- raise Error, 'Unexpected http response code: ' + res.code.to_s unless res.code == 200
45
- resobj = JSON.parse(res.body)
46
- raise Error, 'Received error from Scanpay: ' + resobj['error'] if resobj['error'] != nil
47
- resobj
46
+ res = (data === nil) ? @https.get('https://' + hostname + path, nil, headers) :
47
+ @https.post('https://' + hostname + path, data.to_json, headers)
48
+
49
+ return JSON.parse(res.body) if res.code == 200
50
+ raise Error, res.reason
48
51
  end
49
52
 
50
- def newURL(data)
51
- resobj = request('/new', data, nil)
52
- if !resobj.has_key? 'url'
53
- raise Error, 'Missing url field'
54
- end
55
- resobj['url']
53
+ # newURL: Create a new payment link
54
+ def newURL(data, opts={})
55
+ o = request('/v1/new', data, opts)
56
+ return o['url'] if o['url'].is_a? String
57
+ raise Error, 'invalid response from server'
56
58
  end
57
59
 
58
- def seq(seqnum)
59
- request('/seq/' + seqnum.to_s, nil, nil)
60
+ # seq: Get array of changes since the reqested sequence number
61
+ def seq(num, opts={})
62
+ if !num.is_a? Integer
63
+ raise ArgumentError, 'first argument is not an integer'
64
+ end
65
+ o = request('/v1/seq/' + num.to_s, nil, opts)
66
+ return o if (o['changes'].kind_of? Array) && (o['seq'].is_a? Integer)
67
+ raise Error, 'invalid response from server'
60
68
  end
61
69
 
62
- def handlePing(body, signature)
63
- myrawsig = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), @apikey, body || '')
64
- mysig = Base64.strict_encode64(myrawsig)
65
- raise Error, 'invalid signature' unless consttime_streq(mysig, signature || '')
66
- resobj = JSON.parse(body)
67
- raise Error, 'missing fields' unless [resobj['shopid'], resobj['seq']].all? { |i| i.is_a?(Integer) }
68
- resobj
70
+ # handlePing: Convert body to JSON and validate signature
71
+ def handlePing(body='', signature='')
72
+ digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), @apikey, body)
73
+ is_valid = timesafe_equals(Base64.strict_encode64(digest), signature)
74
+ raise Error, 'invalid signature' unless is_valid
75
+
76
+ o = JSON.parse(body)
77
+ return o if (o['shopid'].is_a? Integer) && (o['seq'].is_a? Integer)
78
+ raise Error, 'invalid ping'
69
79
  end
70
- private :request, :consttime_streq
80
+
81
+ private :request
71
82
  end
72
83
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scanpay
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scanpay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-28 00:00:00.000000000 Z
11
+ date: 2017-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httpclient
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.8'
19
+ version: '2.6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.8'
26
+ version: '2.6'
27
27
  description: Accept payments with the Scanpay payment gateway. See https://scanpay.dk
28
28
  for more details.
29
29
  email: contact@scanpay.dk
@@ -31,16 +31,15 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - ".gitignore"
35
- - LICENSE
36
34
  - lib/scanpay.rb
37
- - tests/newURL.rb
38
- - tests/ping.rb
39
- - tests/seq.rb
40
- homepage: https://github.com/scanpaydk/ruby-scanpay
35
+ homepage: https://scanpay.dk
41
36
  licenses:
42
37
  - MIT
43
- metadata: {}
38
+ metadata:
39
+ bug_tracker_uri: https://github.com/scanpaydk/ruby-scanpay/issues
40
+ documentation_uri: https://docs.scanpay.dk
41
+ homepage_uri: https://scanpay.dk
42
+ source_code_uri: https://github.com/scanpaydk/ruby-scanpay
44
43
  post_install_message:
45
44
  rdoc_options: []
46
45
  require_paths:
@@ -49,7 +48,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
49
48
  requirements:
50
49
  - - ">="
51
50
  - !ruby/object:Gem::Version
52
- version: '0'
51
+ version: 2.0.0
53
52
  required_rubygems_version: !ruby/object:Gem::Requirement
54
53
  requirements:
55
54
  - - ">="
@@ -57,11 +56,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
56
  version: '0'
58
57
  requirements: []
59
58
  rubyforge_project:
60
- rubygems_version: 2.6.10
59
+ rubygems_version: 2.5.2.1
61
60
  signing_key:
62
61
  specification_version: 4
63
62
  summary: Ruby bindings for the Scanpay API
64
- test_files:
65
- - tests/newURL.rb
66
- - tests/ping.rb
67
- - tests/seq.rb
63
+ test_files: []
data/.gitignore DELETED
@@ -1,50 +0,0 @@
1
- *.gem
2
- *.rbc
3
- /.config
4
- /coverage/
5
- /InstalledFiles
6
- /pkg/
7
- /spec/reports/
8
- /spec/examples.txt
9
- /test/tmp/
10
- /test/version_tmp/
11
- /tmp/
12
-
13
- # Used by dotenv library to load environment variables.
14
- # .env
15
-
16
- ## Specific to RubyMotion:
17
- .dat*
18
- .repl_history
19
- build/
20
- *.bridgesupport
21
- build-iPhoneOS/
22
- build-iPhoneSimulator/
23
-
24
- ## Specific to RubyMotion (use of CocoaPods):
25
- #
26
- # We recommend against adding the Pods directory to your .gitignore. However
27
- # you should judge for yourself, the pros and cons are mentioned at:
28
- # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
- #
30
- # vendor/Pods/
31
-
32
- ## Documentation cache and generated files:
33
- /.yardoc/
34
- /_yardoc/
35
- /doc/
36
- /rdoc/
37
-
38
- ## Environment normalization:
39
- /.bundle/
40
- /vendor/bundle
41
- /lib/bundler/man/
42
-
43
- # for a library or gem, you might want to ignore these files since the code is
44
- # intended to run in multiple environments; otherwise, check them in:
45
- # Gemfile.lock
46
- # .ruby-version
47
- # .ruby-gemset
48
-
49
- # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
- .rvmrc
data/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2017 scanpay
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,46 +0,0 @@
1
- require '../lib/scanpay'
2
-
3
- client = Scanpay::Client.new(' API KEY ')
4
- data = {
5
- 'orderid' => 'a766409',
6
- 'language' => 'da',
7
- 'successurl' => 'https://insertyoursuccesspage.dk',
8
- 'items' => [
9
- {
10
- 'name' => 'Pink Floyd: The Dark Side Of The Moon',
11
- 'quantity' => 2,
12
- 'price' => '99.99 DKK',
13
- 'sku' => 'fadf23',
14
- }, {
15
- 'name' => '巨人宏偉的帽子',
16
- 'quantity' => 2,
17
- 'price' => '420 DKK',
18
- 'sku' => '124',
19
- },
20
- ],
21
- 'billing' => {
22
- 'name' => 'John Doe',
23
- 'company' => 'The Shop A/S',
24
- 'email' => 'john@doe.com',
25
- 'phone' => '+4512345678',
26
- 'address' => ['Langgade 23, 2. th'],
27
- 'city' => 'Havneby',
28
- 'zip' => '1234',
29
- 'state' => '',
30
- 'country' => 'DK',
31
- 'vatin' => '35413308',
32
- 'gln' => '7495563456235',
33
- },
34
- 'shipping' => {
35
- 'name' => 'Jan Dåh',
36
- 'company' => 'The Choppa A/S',
37
- 'email' => 'jan@doh.com',
38
- 'phone' => '+4587654321',
39
- 'address' => ['Langgade 23, 1. th', 'C/O The Choppa'],
40
- 'city' => 'Haveby',
41
- 'zip' => '1235',
42
- 'state' => '',
43
- 'country' => 'DK',
44
- },
45
- }
46
- puts "Generated payment url: #{client.newURL(data)}"
@@ -1,13 +0,0 @@
1
- require 'webrick'
2
- require '../lib/scanpay'
3
-
4
- client = Scanpay::Client.new(' API KEY ')
5
-
6
- server = WEBrick::HTTPServer.new :Port => 8080
7
- server.mount_proc '/' do |req, res|
8
- ping = client.handlePing(req.body(), req.header['x-signature'][0])
9
- puts 'Succesfully received ping: shopid=' + ping['shopid'].to_s + ', seq=' + ping['seq'].to_s
10
- end
11
-
12
- trap 'INT' do server.shutdown end
13
- server.start
@@ -1,18 +0,0 @@
1
- require '../lib/scanpay'
2
-
3
- client = Scanpay::Client.new(' API KEY ')
4
- seqobj = client.seq(3)
5
-
6
- puts "After applying the changes your system will be at seq=#{seqobj['seq'].to_s}"
7
- puts "Listing transaction changes(#{seqobj['changes'].length}) since old seq:"
8
- seqobj['changes'].each do |trn|
9
- puts " Tranaction id: #{trn['id'].to_s}"
10
- if trn['error']
11
- puts " Encountered error: #{trn['error']}"
12
- next
13
- end
14
- puts " Order id: #{trn['orderid']}"
15
- puts " Authorized: #{trn['totals']['authorized'].to_s}"
16
- puts " Captured: #{trn['totals']['captured'].to_s}"
17
- puts " Refunded: #{trn['totals']['refunded']}\n\n"
18
- end