ruby-saml 0.8.9 → 0.8.14
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.
Potentially problematic release.
This version of ruby-saml might be problematic. Click here for more details.
- data/Gemfile +11 -1
- data/Rakefile +0 -14
- data/lib/onelogin/ruby-saml/authrequest.rb +84 -18
- data/lib/onelogin/ruby-saml/logoutrequest.rb +93 -18
- data/lib/onelogin/ruby-saml/logoutresponse.rb +1 -24
- data/lib/onelogin/ruby-saml/response.rb +206 -11
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +73 -12
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +158 -0
- data/lib/onelogin/ruby-saml/utils.rb +169 -0
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +2 -1
- data/lib/xml_security.rb +332 -78
- data/test/certificates/ruby-saml-2.crt +15 -0
- data/test/certificates/ruby-saml.crt +14 -0
- data/test/certificates/ruby-saml.key +15 -0
- data/test/logoutrequest_test.rb +177 -44
- data/test/logoutresponse_test.rb +23 -28
- data/test/request_test.rb +100 -37
- data/test/response_test.rb +337 -129
- data/test/responses/adfs_response_xmlns.xml +45 -0
- data/test/responses/encrypted_new_attack.xml.base64 +1 -0
- data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
- data/test/responses/invalids/no_signature.xml.base64 +1 -0
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
- data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/response_with_signed_assertion_3.xml +30 -0
- data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
- data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
- data/test/responses/response_wrapped.xml.base64 +150 -0
- data/test/responses/valid_response.xml.base64 +1 -0
- data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
- data/test/settings_test.rb +5 -5
- data/test/slo_logoutresponse_test.rb +226 -0
- data/test/test_helper.rb +117 -12
- data/test/utils_test.rb +10 -10
- data/test/xml_security_test.rb +354 -68
- metadata +64 -18
- checksums.yaml +0 -7
@@ -1,27 +1,52 @@
|
|
1
|
+
require "xml_security"
|
2
|
+
require "onelogin/ruby-saml/utils"
|
3
|
+
|
1
4
|
module OneLogin
|
2
5
|
module RubySaml
|
3
6
|
class Settings
|
4
|
-
def initialize(overrides = {})
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
def initialize(overrides = {}, keep_security_attributes = false)
|
8
|
+
if keep_security_attributes
|
9
|
+
security_attributes = overrides.delete(:security) || {}
|
10
|
+
config = DEFAULTS.merge(overrides)
|
11
|
+
config[:security] = DEFAULTS[:security].merge(security_attributes)
|
12
|
+
else
|
13
|
+
config = DEFAULTS.merge(overrides)
|
14
|
+
end
|
15
|
+
|
16
|
+
config.each do |k,v|
|
17
|
+
acc = "#{k.to_s}=".to_sym
|
18
|
+
if respond_to? acc
|
19
|
+
value = v.is_a?(Hash) ? v.dup : v
|
20
|
+
send(acc, value)
|
21
|
+
end
|
22
|
+
end
|
10
23
|
end
|
11
|
-
|
12
|
-
|
13
|
-
attr_accessor :
|
24
|
+
|
25
|
+
#idp data
|
26
|
+
attr_accessor :idp_sso_target_url
|
27
|
+
attr_accessor :idp_cert_fingerprint
|
28
|
+
attr_accessor :idp_cert
|
14
29
|
attr_accessor :idp_slo_target_url
|
30
|
+
#sp data
|
31
|
+
attr_accessor :sp_entity_id
|
32
|
+
attr_accessor :assertion_consumer_service_url
|
33
|
+
attr_accessor :authn_context
|
34
|
+
attr_accessor :sp_name_qualifier
|
35
|
+
attr_accessor :name_identifier_format
|
15
36
|
attr_accessor :name_identifier_value
|
16
37
|
attr_accessor :name_identifier_value_requested
|
17
38
|
attr_accessor :sessionindex
|
18
39
|
attr_accessor :assertion_consumer_logout_service_url
|
19
40
|
attr_accessor :compress_request
|
41
|
+
attr_accessor :compress_response
|
20
42
|
attr_accessor :double_quote_xml_attribute_values
|
21
43
|
attr_accessor :force_authn
|
22
44
|
attr_accessor :passive
|
23
45
|
attr_accessor :protocol_binding
|
24
|
-
|
46
|
+
attr_accessor :certificate
|
47
|
+
attr_accessor :private_key
|
48
|
+
# Work-flow
|
49
|
+
attr_accessor :security
|
25
50
|
# Compability
|
26
51
|
attr_accessor :issuer
|
27
52
|
attr_accessor :assertion_consumer_logout_service_url
|
@@ -92,14 +117,50 @@ module OneLogin
|
|
92
117
|
@single_logout_service_binding = url
|
93
118
|
end
|
94
119
|
|
120
|
+
# @return [OpenSSL::X509::Certificate|nil] Build the SP certificate from the settings (previously format it)
|
121
|
+
#
|
122
|
+
def get_sp_cert
|
123
|
+
return nil if certificate.nil? || certificate.empty?
|
124
|
+
|
125
|
+
formatted_cert = OneLogin::RubySaml::Utils.format_cert(certificate)
|
126
|
+
OpenSSL::X509::Certificate.new(formatted_cert)
|
127
|
+
end
|
128
|
+
|
129
|
+
# @return [OpenSSL::X509::Certificate|nil] Build the New SP certificate from the settings (previously format it)
|
130
|
+
#
|
131
|
+
def get_sp_cert_new
|
132
|
+
return nil if certificate_new.nil? || certificate_new.empty?
|
133
|
+
|
134
|
+
formatted_cert = OneLogin::RubySaml::Utils.format_cert(certificate_new)
|
135
|
+
OpenSSL::X509::Certificate.new(formatted_cert)
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [OpenSSL::PKey::RSA] Build the SP private from the settings (previously format it)
|
139
|
+
#
|
140
|
+
def get_sp_key
|
141
|
+
return nil if private_key.nil? || private_key.empty?
|
142
|
+
|
143
|
+
formatted_private_key = OneLogin::RubySaml::Utils.format_private_key(private_key)
|
144
|
+
OpenSSL::PKey::RSA.new(formatted_private_key)
|
145
|
+
end
|
146
|
+
|
95
147
|
private
|
96
148
|
|
97
149
|
DEFAULTS = {
|
98
150
|
:compress_request => true,
|
151
|
+
:compress_response => true,
|
99
152
|
:double_quote_xml_attribute_values => false,
|
100
153
|
:assertion_consumer_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST".freeze,
|
101
|
-
:single_logout_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect".freeze
|
102
|
-
|
154
|
+
:single_logout_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect".freeze,
|
155
|
+
:security => {
|
156
|
+
:authn_requests_signed => false,
|
157
|
+
:logout_requests_signed => false,
|
158
|
+
:logout_responses_signed => false,
|
159
|
+
:embed_sign => false,
|
160
|
+
:digest_method => XMLSecurity::Document::SHA1,
|
161
|
+
:signature_method => XMLSecurity::Document::RSA_SHA1
|
162
|
+
}.freeze
|
163
|
+
}.freeze
|
103
164
|
end
|
104
165
|
end
|
105
166
|
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require "base64"
|
2
|
+
require "zlib"
|
3
|
+
require "cgi"
|
4
|
+
require "onelogin/ruby-saml/utils"
|
5
|
+
require "onelogin/ruby-saml/setting_error"
|
6
|
+
|
7
|
+
module OneLogin
|
8
|
+
module RubySaml
|
9
|
+
|
10
|
+
# SAML2 Logout Response (SLO SP initiated)
|
11
|
+
#
|
12
|
+
class SloLogoutresponse
|
13
|
+
|
14
|
+
# Logout Response ID
|
15
|
+
attr_reader :uuid
|
16
|
+
|
17
|
+
# Initializes the Logout Response. A SloLogoutresponse Object.
|
18
|
+
# Asigns an ID, a random uuid.
|
19
|
+
#
|
20
|
+
def initialize
|
21
|
+
@uuid = OneLogin::RubySaml::Utils.uuid
|
22
|
+
end
|
23
|
+
|
24
|
+
# Creates the Logout Response string.
|
25
|
+
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
26
|
+
# @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
|
27
|
+
# @param logout_message [String] The Message to be placed as StatusMessage in the logout response
|
28
|
+
# @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
|
29
|
+
# @return [String] Logout Request string that includes the SAMLRequest
|
30
|
+
#
|
31
|
+
def create(settings, request_id = nil, logout_message = nil, params = {})
|
32
|
+
params = create_params(settings, request_id, logout_message, params)
|
33
|
+
params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
|
34
|
+
saml_response = CGI.escape(params.delete("SAMLResponse"))
|
35
|
+
response_params = "#{params_prefix}SAMLResponse=#{saml_response}"
|
36
|
+
params.each_pair do |key, value|
|
37
|
+
response_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
|
38
|
+
end
|
39
|
+
raise SettingError.new "Invalid settings, idp_slo_target_url is not set!" if settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
|
40
|
+
@logout_url = settings.idp_slo_target_url + response_params
|
41
|
+
end
|
42
|
+
|
43
|
+
# Creates the Get parameters for the logout response.
|
44
|
+
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
45
|
+
# @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
|
46
|
+
# @param logout_message [String] The Message to be placed as StatusMessage in the logout response
|
47
|
+
# @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
|
48
|
+
# @return [Hash] Parameters
|
49
|
+
#
|
50
|
+
def create_params(settings, request_id = nil, logout_message = nil, params = {})
|
51
|
+
# The method expects :RelayState but sometimes we get 'RelayState' instead.
|
52
|
+
# Based on the HashWithIndifferentAccess value in Rails we could experience
|
53
|
+
# conflicts so this line will solve them.
|
54
|
+
relay_state = params[:RelayState] || params['RelayState']
|
55
|
+
|
56
|
+
if relay_state.nil?
|
57
|
+
params.delete(:RelayState)
|
58
|
+
params.delete('RelayState')
|
59
|
+
end
|
60
|
+
|
61
|
+
response_doc = create_logout_response_xml_doc(settings, request_id, logout_message)
|
62
|
+
response_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
|
63
|
+
|
64
|
+
response = ""
|
65
|
+
response_doc.write(response)
|
66
|
+
|
67
|
+
Logging.debug "Created SLO Logout Response: #{response}"
|
68
|
+
|
69
|
+
response = Zlib::Deflate.deflate(response, 9)[2..-5] if settings.compress_response
|
70
|
+
if Base64.respond_to?('strict_encode64')
|
71
|
+
base64_response = Base64.strict_encode64(response)
|
72
|
+
else
|
73
|
+
base64_response = Base64.encode64(response).gsub(/\n/, "")
|
74
|
+
end
|
75
|
+
response_params = {"SAMLResponse" => base64_response}
|
76
|
+
|
77
|
+
if settings.security[:logout_responses_signed] && !settings.security[:embed_sign] && settings.private_key
|
78
|
+
params['SigAlg'] = settings.security[:signature_method]
|
79
|
+
url_string = OneLogin::RubySaml::Utils.build_query(
|
80
|
+
:type => 'SAMLResponse',
|
81
|
+
:data => base64_response,
|
82
|
+
:relay_state => relay_state,
|
83
|
+
:sig_alg => params['SigAlg']
|
84
|
+
)
|
85
|
+
sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
|
86
|
+
signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
|
87
|
+
if Base64.respond_to?('strict_encode64')
|
88
|
+
params['Signature'] = Base64.strict_encode64(signature)
|
89
|
+
else
|
90
|
+
params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
params.each_pair do |key, value|
|
95
|
+
response_params[key] = value.to_s
|
96
|
+
end
|
97
|
+
|
98
|
+
response_params
|
99
|
+
end
|
100
|
+
|
101
|
+
# Creates the SAMLResponse String.
|
102
|
+
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
103
|
+
# @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
|
104
|
+
# @param logout_message [String] The Message to be placed as StatusMessage in the logout response
|
105
|
+
# @return [String] The SAMLResponse String.
|
106
|
+
#
|
107
|
+
def create_logout_response_xml_doc(settings, request_id = nil, logout_message = nil)
|
108
|
+
document = create_xml_document(settings, request_id, logout_message)
|
109
|
+
sign_document(document, settings)
|
110
|
+
end
|
111
|
+
|
112
|
+
def create_xml_document(settings, request_id = nil, logout_message = nil)
|
113
|
+
time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
|
114
|
+
|
115
|
+
response_doc = XMLSecurity::Document.new
|
116
|
+
response_doc.uuid = uuid
|
117
|
+
|
118
|
+
root = response_doc.add_element 'samlp:LogoutResponse', { 'xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol', "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
119
|
+
root.attributes['ID'] = uuid
|
120
|
+
root.attributes['IssueInstant'] = time
|
121
|
+
root.attributes['Version'] = '2.0'
|
122
|
+
root.attributes['InResponseTo'] = request_id unless request_id.nil?
|
123
|
+
root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
|
124
|
+
|
125
|
+
if settings.sp_entity_id != nil
|
126
|
+
issuer = root.add_element "saml:Issuer"
|
127
|
+
issuer.text = settings.sp_entity_id
|
128
|
+
end
|
129
|
+
|
130
|
+
# add success message
|
131
|
+
status = root.add_element 'samlp:Status'
|
132
|
+
|
133
|
+
# success status code
|
134
|
+
status_code = status.add_element 'samlp:StatusCode'
|
135
|
+
status_code.attributes['Value'] = 'urn:oasis:names:tc:SAML:2.0:status:Success'
|
136
|
+
|
137
|
+
# success status message
|
138
|
+
logout_message ||= 'Successfully Signed Out'
|
139
|
+
status_message = status.add_element 'samlp:StatusMessage'
|
140
|
+
status_message.text = logout_message
|
141
|
+
|
142
|
+
response_doc
|
143
|
+
end
|
144
|
+
|
145
|
+
def sign_document(document, settings)
|
146
|
+
# embed signature
|
147
|
+
if settings.security[:logout_responses_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
|
148
|
+
private_key = settings.get_sp_key
|
149
|
+
cert = settings.get_sp_cert
|
150
|
+
document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
|
151
|
+
end
|
152
|
+
|
153
|
+
document
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -1,15 +1,184 @@
|
|
1
|
+
if RUBY_VERSION < '1.9'
|
2
|
+
require 'uuid'
|
3
|
+
else
|
4
|
+
require 'securerandom'
|
5
|
+
end
|
6
|
+
|
7
|
+
require "base64"
|
8
|
+
require "zlib"
|
9
|
+
|
1
10
|
module OneLogin
|
2
11
|
module RubySaml
|
3
12
|
|
4
13
|
# SAML2 Auxiliary class
|
5
14
|
#
|
6
15
|
class Utils
|
16
|
+
@@uuid_generator = UUID.new if RUBY_VERSION < '1.9'
|
17
|
+
|
18
|
+
BASE64_FORMAT = %r(\A([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\Z)
|
19
|
+
|
7
20
|
# Given a REXML::Element instance, return the concatenation of all child text nodes. Assumes
|
8
21
|
# that there all children other than text nodes can be ignored (e.g. comments). If nil is
|
9
22
|
# passed, nil will be returned.
|
10
23
|
def self.element_text(element)
|
11
24
|
element.texts.map(&:value).join if element
|
12
25
|
end
|
26
|
+
|
27
|
+
# Return a properly formatted x509 certificate
|
28
|
+
#
|
29
|
+
# @param cert [String] The original certificate
|
30
|
+
# @return [String] The formatted certificate
|
31
|
+
#
|
32
|
+
def self.format_cert(cert)
|
33
|
+
# don't try to format an encoded certificate or if is empty or nil
|
34
|
+
if cert.respond_to?(:ascii_only?)
|
35
|
+
return cert if cert.nil? || cert.empty? || !cert.ascii_only?
|
36
|
+
else
|
37
|
+
return cert if cert.nil? || cert.empty? || cert.match(/\x0d/)
|
38
|
+
end
|
39
|
+
|
40
|
+
if cert.scan(/BEGIN CERTIFICATE/).length > 1
|
41
|
+
formatted_cert = []
|
42
|
+
cert.scan(/-{5}BEGIN CERTIFICATE-{5}[\n\r]?.*?-{5}END CERTIFICATE-{5}[\n\r]?/m) {|c|
|
43
|
+
formatted_cert << format_cert(c)
|
44
|
+
}
|
45
|
+
formatted_cert.join("\n")
|
46
|
+
else
|
47
|
+
cert = cert.gsub(/\-{5}\s?(BEGIN|END) CERTIFICATE\s?\-{5}/, "")
|
48
|
+
cert = cert.gsub(/\r/, "")
|
49
|
+
cert = cert.gsub(/\n/, "")
|
50
|
+
cert = cert.gsub(/\s/, "")
|
51
|
+
cert = cert.scan(/.{1,64}/)
|
52
|
+
cert = cert.join("\n")
|
53
|
+
"-----BEGIN CERTIFICATE-----\n#{cert}\n-----END CERTIFICATE-----"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return a properly formatted private key
|
58
|
+
#
|
59
|
+
# @param key [String] The original private key
|
60
|
+
# @return [String] The formatted private key
|
61
|
+
#
|
62
|
+
def self.format_private_key(key)
|
63
|
+
# don't try to format an encoded private key or if is empty
|
64
|
+
return key if key.nil? || key.empty? || key.match(/\x0d/)
|
65
|
+
|
66
|
+
# is this an rsa key?
|
67
|
+
rsa_key = key.match("RSA PRIVATE KEY")
|
68
|
+
key = key.gsub(/\-{5}\s?(BEGIN|END)( RSA)? PRIVATE KEY\s?\-{5}/, "")
|
69
|
+
key = key.gsub(/\n/, "")
|
70
|
+
key = key.gsub(/\r/, "")
|
71
|
+
key = key.gsub(/\s/, "")
|
72
|
+
key = key.scan(/.{1,64}/)
|
73
|
+
key = key.join("\n")
|
74
|
+
key_label = rsa_key ? "RSA PRIVATE KEY" : "PRIVATE KEY"
|
75
|
+
"-----BEGIN #{key_label}-----\n#{key}\n-----END #{key_label}-----"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Build the Query String signature that will be used in the HTTP-Redirect binding
|
79
|
+
# to generate the Signature
|
80
|
+
# @param params [Hash] Parameters to build the Query String
|
81
|
+
# @option params [String] :type 'SAMLRequest' or 'SAMLResponse'
|
82
|
+
# @option params [String] :data Base64 encoded SAMLRequest or SAMLResponse
|
83
|
+
# @option params [String] :relay_state The RelayState parameter
|
84
|
+
# @option params [String] :sig_alg The SigAlg parameter
|
85
|
+
# @return [String] The Query String
|
86
|
+
#
|
87
|
+
def self.build_query(params)
|
88
|
+
type, data, relay_state, sig_alg = [:type, :data, :relay_state, :sig_alg].map { |k| params[k]}
|
89
|
+
url_string = "#{type}=#{CGI.escape(data)}"
|
90
|
+
url_string << "&RelayState=#{CGI.escape(relay_state)}" if relay_state
|
91
|
+
url_string << "&SigAlg=#{CGI.escape(sig_alg)}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.uuid
|
95
|
+
RUBY_VERSION < '1.9' ? "_#{@@uuid_generator.generate}" : "_#{SecureRandom.uuid}"
|
96
|
+
end
|
97
|
+
|
98
|
+
# Build the status error message
|
99
|
+
# @param status_code [String] StatusCode value
|
100
|
+
# @param status_message [Strig] StatusMessage value
|
101
|
+
# @return [String] The status error message
|
102
|
+
def self.status_error_msg(error_msg, raw_status_code = nil, status_message = nil)
|
103
|
+
unless raw_status_code.nil?
|
104
|
+
if raw_status_code.include? "|"
|
105
|
+
status_codes = raw_status_code.split(' | ')
|
106
|
+
values = status_codes.collect do |status_code|
|
107
|
+
status_code.split(':').last
|
108
|
+
end
|
109
|
+
printable_code = values.join(" => ")
|
110
|
+
else
|
111
|
+
printable_code = raw_status_code.split(':').last
|
112
|
+
end
|
113
|
+
error_msg << ', was ' + printable_code
|
114
|
+
end
|
115
|
+
|
116
|
+
unless status_message.nil?
|
117
|
+
error_msg << ' -> ' + status_message
|
118
|
+
end
|
119
|
+
|
120
|
+
error_msg
|
121
|
+
end
|
122
|
+
|
123
|
+
# Base64 decode and try also to inflate a SAML Message
|
124
|
+
# @param saml [String] The deflated and encoded SAML Message
|
125
|
+
# @return [String] The plain SAML Message
|
126
|
+
#
|
127
|
+
def self.decode_raw_saml(saml)
|
128
|
+
return saml unless base64_encoded?(saml)
|
129
|
+
|
130
|
+
decoded = decode(saml)
|
131
|
+
begin
|
132
|
+
inflate(decoded)
|
133
|
+
rescue
|
134
|
+
decoded
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Base 64 decode method
|
139
|
+
# @param string [String] The string message
|
140
|
+
# @return [String] The decoded string
|
141
|
+
#
|
142
|
+
def self.decode(string)
|
143
|
+
Base64.decode64(string)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Base 64 encode method
|
147
|
+
# @param string [String] The string
|
148
|
+
# @return [String] The encoded string
|
149
|
+
#
|
150
|
+
def self.encode(string)
|
151
|
+
if Base64.respond_to?('strict_encode64')
|
152
|
+
Base64.strict_encode64(string)
|
153
|
+
else
|
154
|
+
Base64.encode64(string).gsub(/\n/, "")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Check if a string is base64 encoded
|
159
|
+
# @param string [String] string to check the encoding of
|
160
|
+
# @return [true, false] whether or not the string is base64 encoded
|
161
|
+
#
|
162
|
+
def self.base64_encoded?(string)
|
163
|
+
!!string.gsub(/[\r\n]|\\r|\\n|\s/, "").match(BASE64_FORMAT)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Inflate method
|
167
|
+
# @param deflated [String] The string
|
168
|
+
# @return [String] The inflated string
|
169
|
+
#
|
170
|
+
def self.inflate(deflated)
|
171
|
+
Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(deflated)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Deflate method
|
175
|
+
# @param inflated [String] The string
|
176
|
+
# @return [String] The deflated string
|
177
|
+
#
|
178
|
+
def self.deflate(inflated)
|
179
|
+
Zlib::Deflate.deflate(inflated, 9)[2..-5]
|
180
|
+
end
|
181
|
+
|
13
182
|
end
|
14
183
|
end
|
15
184
|
end
|