paypal-sdk-core 0.1.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.
Files changed (34) hide show
  1. data/Gemfile +11 -0
  2. data/README.md +16 -0
  3. data/Rakefile +5 -0
  4. data/lib/generators/paypal/sdk/USAGE +3 -0
  5. data/lib/generators/paypal/sdk/install_generator.rb +17 -0
  6. data/lib/generators/paypal/sdk/templates/paypal.rb +2 -0
  7. data/lib/generators/paypal/sdk/templates/paypal.yml +32 -0
  8. data/lib/paypal-sdk-core.rb +40 -0
  9. data/lib/paypal-sdk/core/api/base.rb +166 -0
  10. data/lib/paypal-sdk/core/api/data_types/base.rb +236 -0
  11. data/lib/paypal-sdk/core/api/data_types/enum.rb +26 -0
  12. data/lib/paypal-sdk/core/api/data_types/simple_types.rb +47 -0
  13. data/lib/paypal-sdk/core/api/merchant.rb +122 -0
  14. data/lib/paypal-sdk/core/api/platform.rb +75 -0
  15. data/lib/paypal-sdk/core/authentication.rb +79 -0
  16. data/lib/paypal-sdk/core/config.rb +138 -0
  17. data/lib/paypal-sdk/core/credential/base.rb +27 -0
  18. data/lib/paypal-sdk/core/credential/certificate.rb +32 -0
  19. data/lib/paypal-sdk/core/credential/signature.rb +22 -0
  20. data/lib/paypal-sdk/core/credential/third_party/subject.rb +25 -0
  21. data/lib/paypal-sdk/core/credential/third_party/token.rb +39 -0
  22. data/lib/paypal-sdk/core/logging.rb +43 -0
  23. data/lib/paypal-sdk/core/util/oauth_signature.rb +64 -0
  24. data/lib/paypal-sdk/core/version.rb +7 -0
  25. data/spec/config/cert_key.pem +33 -0
  26. data/spec/config/paypal.yml +29 -0
  27. data/spec/core/api/data_type_spec.rb +164 -0
  28. data/spec/core/api/merchant_spec.rb +114 -0
  29. data/spec/core/api/platform_spec.rb +107 -0
  30. data/spec/core/config_spec.rb +48 -0
  31. data/spec/core/logging_spec.rb +28 -0
  32. data/spec/log/test.log +84 -0
  33. data/spec/spec_helper.rb +11 -0
  34. metadata +109 -0
@@ -0,0 +1,27 @@
1
+ module PayPal::SDK::Core
2
+ module Credential
3
+
4
+ # Base credential Class for authentication
5
+ class Base
6
+ attr_accessor :username, :password, :app_id, :device_ipaddress, :sandbox_email_address
7
+
8
+ # Initialize authentication configurations
9
+ # === Arguments
10
+ # * <tt>config</tt> -- Configuration object
11
+ def initialize(config)
12
+ self.username = config.username
13
+ self.password = config.password
14
+ self.app_id = config.app_id
15
+ self.device_ipaddress = config.device_ipaddress
16
+ self.sandbox_email_address = config.sandbox_email_address
17
+ end
18
+
19
+ # Return credential properties
20
+ def properties
21
+ { :username => username, :password => password, :app_id => app_id,
22
+ :device_ipaddress => device_ipaddress, :sandbox_email_address => sandbox_email_address }
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ module PayPal::SDK::Core
2
+ module Credential
3
+
4
+ # Certificate class for SSL Certificate authentication
5
+ class Certificate < Base
6
+
7
+ attr_reader :cert_path
8
+
9
+ def initialize(config)
10
+ super
11
+ @cert_path = config.cert_path
12
+ end
13
+
14
+ # Return SSL certificate
15
+ def cert
16
+ @cert ||= OpenSSL::X509::Certificate.new(cert_content)
17
+ end
18
+
19
+ # Return SSL certificate key
20
+ def key
21
+ @key = OpenSSL::PKey::RSA.new(cert_content)
22
+ end
23
+
24
+ private
25
+ # Return certificate content from the configured file.
26
+ def cert_content
27
+ @cert_content ||= File.read(cert_path)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ module PayPal::SDK::Core
2
+ module Credential
3
+ class Signature < Base
4
+
5
+ attr_accessor :signature
6
+
7
+ # Initialize configuration
8
+ # === Argument
9
+ # * <tt>config</tt> -- Configuration object
10
+ def initialize(config)
11
+ super
12
+ self.signature = config.signature
13
+ end
14
+
15
+ # Return properties for authentication
16
+ def properties
17
+ super.merge({ :signature => signature })
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ module PayPal::SDK::Core
2
+ module Credential
3
+ module ThirdParty
4
+ class Subject
5
+
6
+ attr_accessor :subject, :credential
7
+
8
+ # Initialize configuration
9
+ # === Arguments
10
+ # * <tt>credential</tt> -- Credential object
11
+ # * <tt>config</tt> -- Configuration object
12
+ def initialize(credential, config)
13
+ @credential = credential
14
+ @subject = config.subject
15
+ end
16
+
17
+ # Return properties for authentication.
18
+ def properties
19
+ credential.properties.merge( :subject => subject )
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ module PayPal::SDK::Core
2
+ module Credential
3
+ module ThirdParty
4
+ class Token
5
+
6
+ attr_accessor :token, :token_secret, :credential, :url
7
+
8
+ # Initialize Token credentials
9
+ # === Arguments
10
+ # * <tt>credential</tt> -- Credential Object
11
+ # * <tt>config</tt> -- Configuration object
12
+ # * <tt>url</tt> -- Request url
13
+ def initialize(credential, config, url)
14
+ @credential = credential
15
+ @token = config.token
16
+ @token_secret = config.token_secret
17
+ @url = url
18
+ end
19
+
20
+ RemoveProperties = [ :username, :password, :signature ]
21
+
22
+ # Return credential properties for authentication.
23
+ def properties
24
+ certificate_properties = {}
25
+ certificate_properties.delete_if{|k,v| RemoveProperties.include? k }
26
+ certificate_properties.merge( :authorization => oauth_authentication )
27
+ end
28
+
29
+ private
30
+ # Return OAuth authentication string.
31
+ def oauth_authentication
32
+ Util::OauthSignature.new(credential.username, credential.password, token, token_secret, url).
33
+ authorization_string
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ require 'logger'
2
+
3
+ module PayPal::SDK::Core
4
+ # Include Logging module to provide logger functionality.
5
+ # == Configure logger
6
+ # Logging.logger = Logger.new(STDERR)
7
+ #
8
+ # == Example
9
+ # include Logger
10
+ # logger.info "Debug message"
11
+ module Logging
12
+
13
+ # Get logger object
14
+ def logger
15
+ @logger ||= Logging.logger
16
+ end
17
+
18
+ def log_event(message, start_time, end_time = Time.now)
19
+ duration = sprintf("%.3f", end_time - start_time)
20
+ logger.info "[#{duration}] #{message}"
21
+ end
22
+
23
+ class << self
24
+
25
+ # Get or Create configured logger based on the default environment configuration
26
+ def logger
27
+ @logger ||= Logger.new(Config.config.logfile || STDERR)
28
+ end
29
+
30
+ # Set logger directly and clear the loggers cache.
31
+ # === Attributes
32
+ # * <tt>logger</tt> -- Logger object
33
+ # === Example
34
+ # Logging.logger = Logger.new(STDERR)
35
+ def logger=(logger)
36
+ @logger = logger
37
+ end
38
+
39
+ end
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,64 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'openssl'
4
+ require 'base64'
5
+
6
+ module PayPal::SDK::Core
7
+ module Util
8
+ class OauthSignature
9
+ attr_accessor :username, :password, :token, :token_secret, :url, :timestamp
10
+
11
+ def initialize(username, password, token, token_secret, url, timestamp = nil)
12
+ @username = username
13
+ @password = password
14
+ @token = token
15
+ @token_secret = token_secret
16
+ @url = url
17
+ @timestamp = timestamp || Time.now.to_i.to_s
18
+ end
19
+
20
+ def authorization_string
21
+ signature = oauth_signature
22
+ "token=#{token},signature=#{signature},timestamp=#{timestamp}"
23
+ end
24
+
25
+ def oauth_signature
26
+ key = [
27
+ paypal_encode(password),
28
+ paypal_encode(token_secret),
29
+ ].join("&")
30
+
31
+ digest = OpenSSL::HMAC.digest('sha1', key, base_string)
32
+ Base64.encode64(digest).chomp
33
+ end
34
+
35
+ def base_string
36
+ params = {
37
+ "oauth_consumer_key" => username,
38
+ "oauth_version" => "1.0",
39
+ "oauth_signature_method" => "HMAC-SHA1",
40
+ "oauth_token" => token,
41
+ "oauth_timestamp" => timestamp,
42
+ }
43
+ sorted_query_string = params.sort.map{|v| v.join("=") }.join("&")
44
+
45
+ base = [
46
+ "POST",
47
+ paypal_encode(url),
48
+ paypal_encode(sorted_query_string)
49
+ ].join("&")
50
+ base = base.gsub(/%[0-9A-F][0-9A-F]/, &:downcase )
51
+ end
52
+
53
+ # The PayPalURLEncoder java class percent encodes everything other than 'a-zA-Z0-9 _'.
54
+ # Then it converts ' ' to '+'.
55
+ # Ruby's CGI.encode takes care of the ' ' and '*' to satisfy PayPal
56
+ # (but beware, URI.encode percent encodes spaces, and does nothing with '*').
57
+ # Finally, CGI.encode does not encode '.-', which we need to do here.
58
+ def paypal_encode str
59
+ CGI.escape(str).gsub('.', '%2E').gsub('-', '%2D')
60
+ end
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,7 @@
1
+ module PayPal
2
+ module SDK
3
+ module Core
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXAIBAAKBgQCx/rJhKDRYhs9WZj66FA+HidsrKwvep3g+YNbm1fXmjcg2rEmC
3
+ kq71+Ftw9rx0Uz7vmg6vcsASUgOyeNG7mVB1SsXc6j+JAzZsmpzxHI0QKm+nBNTS
4
+ OAp5NWn6NZQfu3BNAJ/Mok/iL3am2DWXV6dU74J66rBpwIJfzs9kmw8ZGwIDAQAB
5
+ AoGAa/V1sCQ4i7FItLjTNv3P5X+h5W74hhXBguQttFj2Ct7YHwEknQPnBt2aaMve
6
+ xhdvxtgELDpHcVU5VNifLU/yUg3+DSr/YkpBWOcNTCt1seW/z5s+jr2fQERQKbyf
7
+ SXWMTqwrQ19iQoCPYaj7Drf68JhksQCaYN650g7+B/QmSBECQQDp6r75fzDtEWrr
8
+ O4Sl9plK6CRLqQQ3LveAw4JV31N2UAqgAYtzRqD6K+SviAVtX9xxuv983qQxsfX4
9
+ ozE9sGXPAkEAwsxwR1s2Acuy10h3Xj6VtnFB3PpUrkSI9c9ZxF4CMf/+AS/b2UEe
10
+ QhH60WHY8ccgKT/DoPWBcEu2o0f9nPw29QJBAI480zHNeMe/Hp+5iliM0fvtmxxy
11
+ wwB3S8L9n4RuD0dTNpLDPbO0D/DvvdhKwtoWP2rcxbx9eaRKTYKKYUfcupsCQAkP
12
+ SQmIjHJ47tBkZmjTsFLT4aRNYDLarSQBiMNBPAjnRwD3INpx1N5tx6SFUHmuMSi5
13
+ 9nc9888tNklRx9HNSSECQHgs9ExBpA6WbRVcgiizOKH7fmNxAB5f6TQ2W1QHMUb+
14
+ UhZpwuDelOIfzJAQUZGTZk8a8uVmyXU5hTf3ZDbrnJ8=
15
+ -----END RSA PRIVATE KEY-----
16
+
17
+ -----BEGIN CERTIFICATE-----
18
+ MIICpjCCAg+gAwIBAgIDD96nMA0GCSqGSIb3DQEBBQUAMIGfMQswCQYDVQQGEwJV
19
+ UzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxFTATBgNV
20
+ BAoTDFBheVBhbCwgSW5jLjEWMBQGA1UECxQNc2FuZGJveF9jZXJ0czEbMBkGA1UE
21
+ AxQSc2FuZGJveF9jYW1lcmNoYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwu
22
+ Y29tMB4XDTA5MTAxNTA2Mzg1N1oXDTE5MTAxMzA2Mzg1N1owgYAxLTArBgNVBAMU
23
+ JHBsYXRmb18xMjU1MTcwNjk0X2Jpel9hcGkxLmdtYWlsLmNvbTEiMCAGA1UEChMZ
24
+ cGxhdGZvcm0gc2RrJ3MgVGVzdCBTdG9yZTERMA8GA1UEBxMIU2FuIEpvc2UxCzAJ
25
+ BgNVBAgTAkNBMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
26
+ gYEAsf6yYSg0WIbPVmY+uhQPh4nbKysL3qd4PmDW5tX15o3INqxJgpKu9fhbcPa8
27
+ dFM+75oOr3LAElIDsnjRu5lQdUrF3Oo/iQM2bJqc8RyNECpvpwTU0jgKeTVp+jWU
28
+ H7twTQCfzKJP4i92ptg1l1enVO+CeuqwacCCX87PZJsPGRsCAwEAAaMNMAswCQYD
29
+ VR0TBAIwADANBgkqhkiG9w0BAQUFAAOBgQCgH3kwXMJtcAaCBQLKz5TGFogJp/C3
30
+ 06MvjYzdbDrx9Rjf/252UhD8dMPUP5FhU1KXduL+KIEYawPbDQ9+lV58JgM12R0p
31
+ EhCODDI/lDvzbfxUnYgkJ5cnFhTZpcAqVzWuinUnG8jAL9XKiEyu/C73ePMPWPbt
32
+ otoWi+Tk828Qlw==
33
+ -----END CERTIFICATE-----
@@ -0,0 +1,29 @@
1
+ test: &default
2
+ username: jb-us-seller_api1.paypal.com
3
+ password: WX4WTU3S8MY44S7F
4
+ signature: AFcWxV21C7fd0v3bYYYRCpSSRl31A7yDhhsPUU2XhtMoZXsWHFxu-RWy
5
+ app_id: APP-80W284485P519543T
6
+ http_timeout: 30
7
+ mode: sandbox
8
+ sandbox_email_address: Platform.sdk.seller@gmail.com
9
+ logfile: spec/log/test.log
10
+
11
+ development:
12
+ <<: *default
13
+
14
+ with_certificate:
15
+ <<: *default
16
+ username: platfo_1255170694_biz_api1.gmail.com
17
+ password: 2DPPKUPKB7DQLXNR
18
+ signature:
19
+ cert_path: <%= File.expand_path("../cert_key.pem", __FILE__) %>
20
+ app_id: APP-80W284485P519543T
21
+
22
+ with_oauth_token:
23
+ <<: *default
24
+ token: ESTy2hio5WJQo1iixkH29I53RJxaS0Gvno1A6.YQXZgktxbY4I2Tdg
25
+ token_secret: ZKPhUYuwJwYsfWdzorozWO2U9pI
26
+
27
+ with_proxy:
28
+ <<: *default
29
+ http_proxy: <%= ENV['http_proxy'] %>
@@ -0,0 +1,164 @@
1
+ require 'spec_helper'
2
+
3
+ describe PayPal::SDK::Core::API::DataTypes::Base do
4
+
5
+ DataType = PayPal::SDK::Core::API::DataTypes::Base
6
+
7
+ class TestCurrency < DataType
8
+
9
+ # Members
10
+ object_of :amount, String
11
+ object_of :type, String, :namespace => "ns"
12
+ # Attributes
13
+ add_attribute :code
14
+ end
15
+
16
+ class TestType < DataType
17
+ object_of :fromCurrency, TestCurrency
18
+ array_of :toCurrency, TestCurrency
19
+ object_of :firstname, String, :name => "first-name"
20
+ end
21
+
22
+ class TestSimpleType < DataType
23
+ include PayPal::SDK::Core::API::DataTypes::SimpleTypes
24
+ object_of :created_on, Date
25
+ object_of :created_at, DateTime
26
+ end
27
+
28
+ it "should create member object automatically" do
29
+ test_type = TestType.new
30
+ test_type.fromCurrency.should be_a TestCurrency
31
+ test_type.toCurrency.should be_a Array
32
+ test_type.toCurrency[0].should be_a TestCurrency
33
+ test_type.toCurrency[1].should be_a TestCurrency
34
+ test_type.toCurrency[0].amount.should eql nil
35
+ test_type.fromCurrency.amount.should eql nil
36
+ test_type.fromCurrency.type.should eql nil
37
+ end
38
+
39
+ it "should convert the given data to configured type" do
40
+ test_type = TestType.new( :fromCurrency => { :code => "USD", :amount => "50.0"})
41
+ test_type.fromCurrency.should be_a TestCurrency
42
+ test_type.fromCurrency.code.should eql "USD"
43
+ test_type.fromCurrency.amount.should eql "50.0"
44
+ end
45
+
46
+ it "should allow block with initializer" do
47
+ test_type = TestType.new do
48
+ fromCurrency do
49
+ self.code = "USD"
50
+ self.amount = "50.0"
51
+ end
52
+ end
53
+ test_type.fromCurrency.code.should eql "USD"
54
+ test_type.fromCurrency.amount.should eql "50.0"
55
+ end
56
+
57
+ it "should allow block with member" do
58
+ test_type = TestType.new
59
+ test_type.fromCurrency do
60
+ self.code = "USD"
61
+ self.amount = "50.0"
62
+ end
63
+ test_type.fromCurrency.code.should eql "USD"
64
+ test_type.fromCurrency.amount.should eql "50.0"
65
+ end
66
+
67
+ it "should assign value to attribute" do
68
+ test_currency = TestCurrency.new( :@code => "USD", :amount => "50" )
69
+ test_currency.code.should eql "USD"
70
+ end
71
+
72
+ it "should allow configured Class object" do
73
+ test_currency = TestCurrency.new( :code => "USD", :amount => "50" )
74
+ test_type = TestType.new( :fromCurrency => test_currency )
75
+ test_type.fromCurrency.should eql test_currency
76
+ end
77
+
78
+ it "should allow snakecase" do
79
+ test_type = TestType.new( :from_currency => {} )
80
+ test_type.from_currency.should be_a TestCurrency
81
+ test_type.from_currency.should eql test_type.fromCurrency
82
+ end
83
+
84
+ it "should allow array" do
85
+ test_type = TestType.new( :toCurrency => [{ :code => "USD", :amount => "50.0" }] )
86
+ test_type.toCurrency.should be_a Array
87
+ test_type.toCurrency.first.should be_a TestCurrency
88
+ end
89
+
90
+ it "should allow only configured fields" do
91
+ lambda do
92
+ TestType.new( :notExist => "testing")
93
+ end.should raise_error
94
+ end
95
+
96
+ it "should not convert empty hash" do
97
+ test_type = TestType.new( :fromCurrency => {} )
98
+ test_type.to_hash.should eql({})
99
+ end
100
+
101
+ it "should not convert empty array" do
102
+ test_type = TestType.new( :toCurrency => [] )
103
+ test_type.to_hash.should eql({})
104
+ end
105
+
106
+ it "should not convert array of empty hash" do
107
+ test_type = TestType.new( :toCurrency => [ {} ] )
108
+ test_type.to_hash.should eql({})
109
+ end
110
+
111
+ it "should return empty hash" do
112
+ test_type = TestType.new
113
+ test_type.to_hash.should eql({})
114
+ end
115
+
116
+ it "should convert to hash" do
117
+ test_currency = TestCurrency.new(:amount => "500")
118
+ test_currency.to_hash.should eql(:amount => "500")
119
+ end
120
+
121
+ it "should convert to hash with key as string" do
122
+ test_currency = TestCurrency.new(:amount => "500")
123
+ test_currency.to_hash(:symbol => false).should eql("amount" => "500")
124
+ end
125
+
126
+ it "should convert attribute key with @" do
127
+ test_currency = TestCurrency.new( :code => "USD", :amount => "50" )
128
+ test_currency.to_hash[:@code].should eql "USD"
129
+ end
130
+
131
+ it "should convert attribute key without @" do
132
+ test_currency = TestCurrency.new( :code => "USD", :amount => "50" )
133
+ test_currency.to_hash(:attribute => false)[:code].should eql "USD"
134
+ end
135
+
136
+ it "should convert to hash with namespace" do
137
+ test_currency = TestCurrency.new(:amount => "500", :type => "USD" )
138
+ hash = test_currency.to_hash
139
+ hash[:amount].should eql "500"
140
+ hash[:"ns:type"].should eql "USD"
141
+ hash = test_currency.to_hash(:namespace => false)
142
+ hash[:amount].should eql "500"
143
+ hash[:type].should eql "USD"
144
+ end
145
+
146
+ it "should allow namespace" do
147
+ test_currency = TestCurrency.new(:amount => "500", :"ns:type" => "USD" )
148
+ test_currency.type.should eql "USD"
149
+ end
150
+
151
+ it "should use name option in members" do
152
+ test_type = TestType.new( :firstname => "FirstName")
153
+ test_type.to_hash.should eql({:"first-name" => "FirstName" })
154
+ end
155
+
156
+ it "should allow date" do
157
+ date_time = "2010-10-10T10:10:10"
158
+ test_simple_type = TestSimpleType.new( :created_on => date_time, :created_at => date_time )
159
+ test_simple_type.created_on.should be_a Date
160
+ test_simple_type.created_at.should be_a DateTime
161
+ end
162
+
163
+ end
164
+