paypal-sdk-rest-pmrb 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +15 -0
- data/README.md +265 -0
- data/Rakefile +15 -0
- data/data/DigiCertHighAssuranceEVRootCA.pem +23 -0
- data/data/DigiCertSHA2ExtendedValidationServerCA.pem +28 -0
- data/data/paypal.crt +193 -0
- data/lib/generators/paypal/sdk/USAGE +3 -0
- data/lib/generators/paypal/sdk/install_generator.rb +17 -0
- data/lib/generators/paypal/sdk/templates/paypal.rb +2 -0
- data/lib/generators/paypal/sdk/templates/paypal.yml +29 -0
- data/lib/paypal-sdk-core.rb +38 -0
- data/lib/paypal-sdk-rest.rb +2 -0
- data/lib/paypal-sdk/core/api.rb +20 -0
- data/lib/paypal-sdk/core/api/base.rb +169 -0
- data/lib/paypal-sdk/core/api/data_types/array_with_block.rb +44 -0
- data/lib/paypal-sdk/core/api/data_types/base.rb +225 -0
- data/lib/paypal-sdk/core/api/data_types/enum.rb +26 -0
- data/lib/paypal-sdk/core/api/data_types/simple_types.rb +52 -0
- data/lib/paypal-sdk/core/api/ipn.rb +66 -0
- data/lib/paypal-sdk/core/api/rest.rb +177 -0
- data/lib/paypal-sdk/core/authentication.rb +66 -0
- data/lib/paypal-sdk/core/config.rb +253 -0
- data/lib/paypal-sdk/core/credential.rb +16 -0
- data/lib/paypal-sdk/core/credential/base.rb +27 -0
- data/lib/paypal-sdk/core/credential/certificate.rb +32 -0
- data/lib/paypal-sdk/core/credential/signature.rb +22 -0
- data/lib/paypal-sdk/core/credential/third_party/subject.rb +25 -0
- data/lib/paypal-sdk/core/credential/third_party/token.rb +39 -0
- data/lib/paypal-sdk/core/exceptions.rb +112 -0
- data/lib/paypal-sdk/core/logging.rb +50 -0
- data/lib/paypal-sdk/core/openid_connect.rb +140 -0
- data/lib/paypal-sdk/core/openid_connect/api.rb +50 -0
- data/lib/paypal-sdk/core/openid_connect/data_types.rb +73 -0
- data/lib/paypal-sdk/core/openid_connect/get_api.rb +28 -0
- data/lib/paypal-sdk/core/openid_connect/request_data_type.rb +52 -0
- data/lib/paypal-sdk/core/openid_connect/set_api.rb +36 -0
- data/lib/paypal-sdk/core/util.rb +11 -0
- data/lib/paypal-sdk/core/util/http_helper.rb +171 -0
- data/lib/paypal-sdk/core/util/oauth_signature.rb +64 -0
- data/lib/paypal-sdk/core/util/ordered_hash.rb +165 -0
- data/lib/paypal-sdk/rest.rb +39 -0
- data/lib/paypal-sdk/rest/api.rb +23 -0
- data/lib/paypal-sdk/rest/data_types.rb +2597 -0
- data/lib/paypal-sdk/rest/error_hash.rb +39 -0
- data/lib/paypal-sdk/rest/get_api.rb +20 -0
- data/lib/paypal-sdk/rest/request_data_type.rb +53 -0
- data/lib/paypal-sdk/rest/set_api.rb +42 -0
- data/lib/paypal-sdk/rest/version.rb +7 -0
- data/spec/README.md +22 -0
- data/spec/config/cacert.pem +171 -0
- data/spec/config/cert_key.pem +33 -0
- data/spec/config/paypal.yml +35 -0
- data/spec/config/sample_data.yml +3 -0
- data/spec/core/api/data_type_spec.rb +289 -0
- data/spec/core/api/rest_spec.rb +211 -0
- data/spec/core/config_spec.rb +192 -0
- data/spec/core/logging_spec.rb +28 -0
- data/spec/core/openid_connect_spec.rb +153 -0
- data/spec/invoice_examples_spec.rb +38 -0
- data/spec/log/http.log +175 -0
- data/spec/log/rest_http.log +0 -0
- data/spec/payments_examples_spec.rb +437 -0
- data/spec/payouts_examples_spec.rb +74 -0
- data/spec/rest/data_types_spec.rb +62 -0
- data/spec/rest/error_hash_spec.rb +83 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/subscription_examples_spec.rb +227 -0
- data/spec/support/sample_data.rb +5 -0
- data/spec/web_profile_examples_spec.rb +106 -0
- data/spec/webhooks_examples_spec.rb +93 -0
- metadata +177 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require 'paypal-sdk/rest/version'
|
3
|
+
|
4
|
+
module PayPal::SDK
|
5
|
+
module Core
|
6
|
+
module OpenIDConnect
|
7
|
+
class API < Core::API::Base
|
8
|
+
|
9
|
+
DEFAULT_OPENID_ENDPOINT = {
|
10
|
+
:sandbox => "https://api.sandbox.paypal.com",
|
11
|
+
:live => "https://api.paypal.com" }
|
12
|
+
|
13
|
+
def initialize(environment = nil, options = {})
|
14
|
+
super("", environment, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def service_endpoint
|
18
|
+
self.config.openid_endpoint || DEFAULT_OPENID_ENDPOINT[self.api_mode] || DEFAULT_OPENID_ENDPOINT[:sandbox]
|
19
|
+
end
|
20
|
+
|
21
|
+
def format_request(payload)
|
22
|
+
payload[:uri].path = url_join(payload[:uri].path, payload[:action])
|
23
|
+
payload[:body] = encode_www_form(payload[:params]) if payload[:params]
|
24
|
+
payload[:header] = {"Content-Type" => "application/x-www-form-urlencoded" }.merge(payload[:header])
|
25
|
+
payload
|
26
|
+
end
|
27
|
+
|
28
|
+
def format_response(payload)
|
29
|
+
payload[:data] =
|
30
|
+
if payload[:response].code >= "200" and payload[:response].code <= "299"
|
31
|
+
MultiJson.load(payload[:response].body)
|
32
|
+
elsif payload[:response].content_type == "application/json"
|
33
|
+
{ "error" => MultiJson.load(payload[:response].body) }
|
34
|
+
else
|
35
|
+
{ "error" => { "name" => payload[:response].code, "message" => payload[:response].message,
|
36
|
+
"developer_msg" => payload[:response] } }
|
37
|
+
end
|
38
|
+
payload
|
39
|
+
end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
def user_agent
|
43
|
+
@user_agent ||= "PayPalSDK/openid-connect-ruby #{PayPal::SDK::REST::VERSION} (#{sdk_library_details})"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'paypal-sdk-core'
|
2
|
+
|
3
|
+
module PayPal::SDK::Core
|
4
|
+
module OpenIDConnect
|
5
|
+
module DataTypes
|
6
|
+
class Base < PayPal::SDK::Core::API::DataTypes::Base
|
7
|
+
end
|
8
|
+
|
9
|
+
class Address < Base
|
10
|
+
def self.load_members
|
11
|
+
object_of :street_address, String
|
12
|
+
object_of :locality, String
|
13
|
+
object_of :region, String
|
14
|
+
object_of :postal_code, String
|
15
|
+
object_of :country, String
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Userinfo < Base
|
20
|
+
def self.load_members
|
21
|
+
object_of :user_id, String
|
22
|
+
object_of :sub, String
|
23
|
+
object_of :name, String
|
24
|
+
object_of :given_name, String
|
25
|
+
object_of :family_name, String
|
26
|
+
object_of :middle_name, String
|
27
|
+
object_of :picture, String
|
28
|
+
object_of :email, String
|
29
|
+
object_of :email_verified, Boolean
|
30
|
+
object_of :gender, String
|
31
|
+
object_of :birthday, String
|
32
|
+
object_of :zoneinfo, String
|
33
|
+
object_of :locale, String
|
34
|
+
object_of :language, String
|
35
|
+
object_of :verified, Boolean
|
36
|
+
object_of :phone_number, String
|
37
|
+
object_of :address, Address
|
38
|
+
object_of :verified_account, Boolean
|
39
|
+
object_of :account_type, String
|
40
|
+
object_of :account_creation_date, String
|
41
|
+
object_of :age_range, String
|
42
|
+
object_of :payer_id, String
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Tokeninfo < Base
|
47
|
+
def self.load_members
|
48
|
+
object_of :scope, String
|
49
|
+
object_of :access_token, String
|
50
|
+
object_of :refresh_token, String
|
51
|
+
object_of :token_type, String
|
52
|
+
object_of :id_token, String
|
53
|
+
object_of :expires_in, Integer
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Error < Base
|
58
|
+
def self.load_members
|
59
|
+
object_of :error, String
|
60
|
+
object_of :error_description, String
|
61
|
+
object_of :error_uri, String
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
constants.each do |data_type_klass|
|
67
|
+
data_type_klass = const_get(data_type_klass)
|
68
|
+
data_type_klass.load_members if defined? data_type_klass.load_members
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module PayPal::SDK
|
2
|
+
module Core
|
3
|
+
module OpenIDConnect
|
4
|
+
module GetAPI
|
5
|
+
# Get API object
|
6
|
+
# === Example
|
7
|
+
# Payment.api
|
8
|
+
# payment.api
|
9
|
+
def api
|
10
|
+
@api || parent_api
|
11
|
+
end
|
12
|
+
|
13
|
+
# Parent API object
|
14
|
+
def parent_api
|
15
|
+
superclass.respond_to?(:api) ? superclass.api : RequestDataType.api
|
16
|
+
end
|
17
|
+
|
18
|
+
def client_id
|
19
|
+
api.config.openid_client_id || api.config.client_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def client_secret
|
23
|
+
api.config.openid_client_secret || api.config.client_secret
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module PayPal::SDK
|
2
|
+
module Core
|
3
|
+
module OpenIDConnect
|
4
|
+
module RequestDataType
|
5
|
+
|
6
|
+
# Get a local API object or Class level API object
|
7
|
+
def api
|
8
|
+
@api || self.class.api
|
9
|
+
end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Global API object
|
13
|
+
# === Example
|
14
|
+
# RequestDataType.api
|
15
|
+
def api
|
16
|
+
@api ||= API.new({})
|
17
|
+
end
|
18
|
+
|
19
|
+
def client_id
|
20
|
+
api.config.openid_client_id || api.config.client_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def client_secret
|
24
|
+
api.config.openid_client_secret || api.config.client_secret
|
25
|
+
end
|
26
|
+
|
27
|
+
# Setter for RequestDataType.api
|
28
|
+
# === Example
|
29
|
+
# RequestDataType.set_config(..)
|
30
|
+
include SetAPI
|
31
|
+
|
32
|
+
# Configure depended module, when RequestDataType is include.
|
33
|
+
# === Example
|
34
|
+
# class Payment < DataTypes
|
35
|
+
# include RequestDataType
|
36
|
+
# end
|
37
|
+
# Payment.set_config(..)
|
38
|
+
# payment.set_config(..)
|
39
|
+
# Payment.api
|
40
|
+
# payment.api
|
41
|
+
def included(klass)
|
42
|
+
klass.class_eval do
|
43
|
+
extend GetAPI
|
44
|
+
extend SetAPI
|
45
|
+
include SetAPI
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module PayPal::SDK
|
2
|
+
module Core
|
3
|
+
module OpenIDConnect
|
4
|
+
module SetAPI
|
5
|
+
# Set new api
|
6
|
+
# === Examples
|
7
|
+
# payment.set_config(:development)
|
8
|
+
# payment.set_config(:client_id => "XYZ", :client_secret => "SECRET")
|
9
|
+
# payment.set_config
|
10
|
+
# payment.api = API.new(:development)
|
11
|
+
def set_config(*args)
|
12
|
+
if args[0].is_a?(API)
|
13
|
+
@api = args[0]
|
14
|
+
else
|
15
|
+
@api ||= API.new({})
|
16
|
+
@api.set_config(*args) # Just override the configuration and Not
|
17
|
+
@api
|
18
|
+
end
|
19
|
+
end
|
20
|
+
alias_method :config=, :set_config
|
21
|
+
alias_method :set_api, :set_config
|
22
|
+
alias_method :api=, :set_config
|
23
|
+
|
24
|
+
# Override client id
|
25
|
+
def client_id=(client_id)
|
26
|
+
set_config(:client_id => client_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Override client secret
|
30
|
+
def client_secret=(client_secret)
|
31
|
+
set_config(:client_secret => client_secret)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module PayPal
|
2
|
+
module SDK
|
3
|
+
module Core
|
4
|
+
module Util
|
5
|
+
autoload :OauthSignature, "paypal-sdk/core/util/oauth_signature"
|
6
|
+
autoload :OrderedHash, "paypal-sdk/core/util/ordered_hash"
|
7
|
+
autoload :HTTPHelper, "paypal-sdk/core/util/http_helper"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'uri'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module PayPal::SDK::Core
|
6
|
+
module Util
|
7
|
+
module HTTPHelper
|
8
|
+
|
9
|
+
include Configuration
|
10
|
+
include Logging
|
11
|
+
include Authentication
|
12
|
+
include Exceptions
|
13
|
+
|
14
|
+
# Create HTTP connection based on given service name or configured end point
|
15
|
+
def create_http_connection(uri)
|
16
|
+
new_http(uri).tap do |http|
|
17
|
+
if config.http_timeout
|
18
|
+
http.open_timeout = config.http_timeout
|
19
|
+
http.read_timeout = config.http_timeout
|
20
|
+
end
|
21
|
+
configure_ssl(http) if uri.scheme == "https"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# New raw HTTP object
|
26
|
+
def new_http(uri)
|
27
|
+
if config.http_proxy
|
28
|
+
proxy = URI.parse(config.http_proxy)
|
29
|
+
Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user, proxy.password)
|
30
|
+
else
|
31
|
+
Net::HTTP.new(uri.host, uri.port)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Default ca file
|
36
|
+
def default_ca_file
|
37
|
+
File.expand_path("../../../../../data/paypal.crt", __FILE__)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Apply ssl configuration to http object
|
41
|
+
def configure_ssl(http)
|
42
|
+
http.tap do |https|
|
43
|
+
https.use_ssl = true
|
44
|
+
https.ca_file = default_ca_file
|
45
|
+
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
46
|
+
begin
|
47
|
+
https.ssl_version = :TLSv1_2
|
48
|
+
rescue => error
|
49
|
+
logger.warn("WARNING: Your system does not support TLSv1.2. Per PCI Security Council mandate (https://github.com/paypal/TLS-update), you MUST update to latest security library.")
|
50
|
+
end
|
51
|
+
config.ssl_options.each do |key, value|
|
52
|
+
http.send("#{key}=", value)
|
53
|
+
end
|
54
|
+
add_certificate(https)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Join url
|
59
|
+
def url_join(path, action)
|
60
|
+
path.sub(/\/?$/, "/#{action}")
|
61
|
+
end
|
62
|
+
|
63
|
+
# Make Http call
|
64
|
+
# * payload - Hash(:http, :method, :uri, :body, :header)
|
65
|
+
def http_call(payload)
|
66
|
+
response =
|
67
|
+
log_http_call(payload) do
|
68
|
+
http = payload[:http] || create_http_connection(payload[:uri])
|
69
|
+
http.start do |session|
|
70
|
+
if [ :get, :delete, :head ].include? payload[:method]
|
71
|
+
session.send(payload[:method], payload[:uri].request_uri, payload[:header])
|
72
|
+
else
|
73
|
+
session.send(payload[:method], payload[:uri].request_uri, payload[:body], payload[:header])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
handle_response(response)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Log Http call
|
82
|
+
# * payload - Hash(:http, :method, :uri, :body, :header)
|
83
|
+
def log_http_call(payload)
|
84
|
+
logger.info "Request[#{payload[:method]}]: #{payload[:uri].to_s}"
|
85
|
+
|
86
|
+
logger.debug "Request.body=#{payload[:body]}\trequest.header=#{payload[:header]}"
|
87
|
+
|
88
|
+
start_time = Time.now
|
89
|
+
response = yield
|
90
|
+
logger.info sprintf("Response[%s]: %s, Duration: %.3fs", response.code,
|
91
|
+
response.message, Time.now - start_time)
|
92
|
+
|
93
|
+
logger.add(
|
94
|
+
response_details_log_level(response),
|
95
|
+
"Response.body=#{response.body}\tResponse.header=#{response.to_hash}"
|
96
|
+
)
|
97
|
+
|
98
|
+
response
|
99
|
+
end
|
100
|
+
|
101
|
+
# Generate header based on given header keys and properties
|
102
|
+
# === Arguments
|
103
|
+
# * <tt>header_keys</tt> -- List of Header keys for the properties
|
104
|
+
# * <tt>properties</tt> -- properties
|
105
|
+
# === Return
|
106
|
+
# Hash with header as key property as value
|
107
|
+
# === Example
|
108
|
+
# map_header_value( { :username => "X-PAYPAL-USERNAME"}, { :username => "guest" })
|
109
|
+
# # Return: { "X-PAYPAL-USERNAME" => "guest" }
|
110
|
+
def map_header_value(header_keys, properties)
|
111
|
+
header = {}
|
112
|
+
properties.each do |key, value|
|
113
|
+
key = header_keys[key]
|
114
|
+
header[key] = value.to_s if key and value
|
115
|
+
end
|
116
|
+
header
|
117
|
+
end
|
118
|
+
|
119
|
+
def encode_www_form(hash)
|
120
|
+
if defined? URI.encode_www_form
|
121
|
+
URI.encode_www_form(hash)
|
122
|
+
else
|
123
|
+
hash.map{|key, value| "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}" }.join("&")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Handles response and error codes from the remote service.
|
128
|
+
def handle_response(response)
|
129
|
+
case response.code.to_i
|
130
|
+
when 301, 302, 303, 307
|
131
|
+
raise(Redirection.new(response))
|
132
|
+
when 200...400
|
133
|
+
response
|
134
|
+
when 400
|
135
|
+
raise(BadRequest.new(response))
|
136
|
+
when 401
|
137
|
+
raise(UnauthorizedAccess.new(response))
|
138
|
+
when 403
|
139
|
+
raise(ForbiddenAccess.new(response))
|
140
|
+
when 404
|
141
|
+
raise(ResourceNotFound.new(response))
|
142
|
+
when 405
|
143
|
+
raise(MethodNotAllowed.new(response))
|
144
|
+
when 409
|
145
|
+
raise(ResourceConflict.new(response))
|
146
|
+
when 410
|
147
|
+
raise(ResourceGone.new(response))
|
148
|
+
when 422
|
149
|
+
raise(ResourceInvalid.new(response))
|
150
|
+
when 401...500
|
151
|
+
raise(ClientError.new(response))
|
152
|
+
when 500...600
|
153
|
+
raise(ServerError.new(response))
|
154
|
+
else
|
155
|
+
raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
def response_details_log_level(response)
|
162
|
+
if (400...600).cover?(response.code.to_i)
|
163
|
+
Logger::WARN
|
164
|
+
else
|
165
|
+
Logger::DEBUG
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -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("&").gsub(/%[0-9A-F][0-9A-F]/, &:downcase )
|
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.to_s).gsub('.', '%2E').gsub('-', '%2D')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|