yodlee_wrap 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 333e83243a0aa385ef387bdcdea95b1b6e8d3d93
4
+ data.tar.gz: 46f43b8085cf36b894ad595788b3b15367d325de
5
+ SHA512:
6
+ metadata.gz: 378bae78d518fa9311b3ca23f2aee56e8f0ad5aa32dcc22d5c10e58ac191bb686ec4bf749730f4f6ca7988347bb1a10baf1848d0faacc9f04931508b953dfcd7
7
+ data.tar.gz: 87d2975006769dd6f8070a994ea3cdbeb6c5a31865380f50869e1667da86d11c14a569d6a55d3406104682a3ef6c10c5326f0e21885ea09cd5c499a354c3947b
data/.DS_Store ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .env
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format doc
3
+ --tag ~skip
4
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in yodleeicious.gemspec
4
+ gemspec
5
+
6
+ gem 'faraday', '0.9.1'
7
+ gem 'faraday_middleware', '~>0.9.1'
8
+ gem 'socksify', '~>1.6.0'
9
+ gem 'dotenv'
10
+ gem 'byebug'
11
+
12
+ group :development, :test do
13
+ gem "codeclimate-test-reporter"
14
+ gem "guard-rspec"
15
+ gem 'rspec-its'
16
+ end
data/Guardfile ADDED
@@ -0,0 +1,16 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ # Note: The cmd option is now required due to the increasing number of ways
5
+ # rspec may be run, below are examples of the most common uses.
6
+ # * bundler: 'bundle exec rspec'
7
+ # * bundler binstubs: 'bin/rspec'
8
+ # * spring: 'bin/rsspec' (This will use spring if running and you have
9
+ # installed the spring binstubs per the docs)
10
+ # * zeus: 'zeus rspec' (requires the server to be started separetly)
11
+ # * 'just' rspec: 'rspec'
12
+ guard :rspec, cmd: "bundle exec rspec" do
13
+ watch(%r{^spec/(.+)_spec\.rb$})
14
+ watch('spec/spec_helper.rb') { "spec" }
15
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
16
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Drew Nichols
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,176 @@
1
+
2
+ # Yodlee-icious
3
+ [![Gem Version](https://badge.fury.io/rb/yodlee-icious.svg)](http://badge.fury.io/rb/yodlee-icious) [![Code Climate](https://codeclimate.com/repos/556dcf7fe30ba00903005872/badges/9398ac76dbcae2084eeb/gpa.svg)](https://codeclimate.com/repos/556dcf7fe30ba00903005872/feed) [![Test Coverage](https://codeclimate.com/repos/556dcf7fe30ba00903005872/badges/9398ac76dbcae2084eeb/coverage.svg)](https://codeclimate.com/repos/556dcf7fe30ba00903005872/coverage)
4
+ [ ![Codeship Status for liftforward/yodlee-icious](https://codeship.com/projects/71603f00-9393-0132-dcd0-1a9a253548c0/status?branch=master)](https://codeship.com/projects/62288)
5
+
6
+ Yodlee-icious (formally Yodlicious) is a ruby gem wrapping the Yodlee REST(ish) API. We had to build this for our integration with Yodlee which was somewhat more painful than it should have been so we figured we share to be a good neighbor.
7
+
8
+ ![image of yodleeicious](https://github.com/liftforward/yodlee-icious/blob/master/yodlicious.png)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'yodlee-icious'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle install
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install yodlee-icious
25
+
26
+ ## Usage
27
+
28
+ ### Configuration
29
+
30
+ We needed to use the Yodlee API both within a rails app and outside with multiple Yodlee connections concurrently. As such we provided both the option for a global default configuration and a instance specific configuration. For instance specific:
31
+
32
+ ```ruby
33
+ require "yodleeicious"
34
+
35
+ config = {
36
+ cobranded_username: your_username,
37
+ cobranded_password: your_password
38
+ }
39
+
40
+ yodlee_api = YodleeWrap::YodleeApi.new(config)
41
+
42
+ ```
43
+ When in a Rails app it can be more convenient to use a global default configuration. To use global defaults:
44
+
45
+ ```ruby
46
+ #/<myproject>/config/initializers/yodleeicious.rb
47
+ require 'yodleeicious'
48
+
49
+ #setting default configurations for Yodleeicious
50
+ Yodleeicious::Config.base_url = ENV['YODLEE_BASE_URL']
51
+ Yodleeicious::Config.cobranded_username = ENV['YODLEE_COBRANDED_USERNAME']
52
+ Yodleeicious::Config.cobranded_password = ENV['YODLEE_COBRANDED_PASSWORD']
53
+
54
+ #setting yodleeicious logger to use the Rails logger
55
+ Yodleeicious::Config.logger = Rails.logger
56
+ ```
57
+ and wherever you want to use the api simply create a new one and it will pickup the global defaults.
58
+
59
+ ```ruby
60
+ yodlee_api = Yodleeicious::YodleeApi.new
61
+ ```
62
+ If for any reason you need to, you can pass a hash into the constructor and it will use any provided hash values over the defaults. Note this is done on each value not the entire hash.
63
+
64
+ You can also update an existing instances of the YodleeApi's configuration with the configure method. For example:
65
+
66
+ ```ruby
67
+
68
+ yodlee_api = Yodleeicious::YodleeApi.new { base_url: 'http://yodlee.com/blablabla' }
69
+
70
+ yodlee_api.configure { base_url: 'https://secure.yodlee.com/blablabla }
71
+
72
+ puts yodlee_api.base_url
73
+ ```
74
+ will output
75
+
76
+ ```
77
+ https://secure.yodlee.com/blablabla
78
+ ```
79
+
80
+ ### Configuring the proxy
81
+
82
+ If you're Yodlee account is like ours Yodlee will whitelist certain IPs for access and you'll need to proxy all of your API requests through that IP. You can set the proxy with the proxy_url key. Currently the proxy supports, http, https, and socks proxies. Simply set the proxy_url property in the config hash passed to YodleeApi and it should begin using the proxy. For example:
83
+
84
+ ```
85
+ config = {
86
+ base_url: "https://consolidatedsdk.yodlee.com/yodsoap/srest/my-cobranded-path/v1.0",
87
+ cobranded_username: "my-cobranded-user",
88
+ cobranded_password: "my-cobranded-password",
89
+ proxy_url: "https://my-proxy-server-on-the-whitelist:my=proxy-port/"
90
+ }
91
+
92
+ yodlee_api = Yodleeicious::YodleeApi.new(config)
93
+ ```
94
+
95
+ ## Working with the API
96
+
97
+ The Yodlee Api responses are somewhat varied (especially the errors) and as such we build Yodleeicious as a pretty thin layer around their request/response model. We didn't attempt to map all their JSON responses into models or anything fancy like that. Instead we simply created a method for each API endpoint which takes the required parameters and return a response object. That said, Response object does provide some conveniences to make up for the inconsistent delivery of errors from Yodlee's APIs.
98
+
99
+ ### Starting your cobranded session
100
+
101
+ Once you've configured an instance of the YodleeAPI the first thing you must do is start a Yodlee cobranded session. This is also a good rails console test to see if everything is configured correctly:
102
+
103
+ ```ruby
104
+ pry(main)> yodlee_api = Yodleeicious::YodleeApi.new
105
+ pry(main)> response = yodlee_api.cobranded_login
106
+ pry(main)> response.success?
107
+ => true
108
+ ```
109
+ As you probably suspect the call to cobranded_login wraps the ```/authenticate/coblogin``` endpoint call. If this is a success the YodleeApi instance will cache the cobranded session id yodlee returned and use it on all subsequent api calls. You can also access this value if desired with YodleeApi#cobranded_session_token.
110
+
111
+ ```
112
+ pry(main)> yodlee_api.cobranded_session_token
113
+ => "12162013_1:a0b1ac3e32a2e656f8f5bd21de23ae1721ffd9dab8bee9f29811f5959bbf102f16c98354eba252bb030dc96e267bd2489a40562f18e09ee8ba9038d19280cc43"
114
+ ```
115
+ At this point something has probably gone wrong for you and you want to see the response json from ```/authenticate/coblogin```. To do this simply use ```response#body```.
116
+
117
+ ```
118
+ pry(main)> response.body
119
+ => {"Error"=>[{"errorDetail"=>"Invalid Cobrand Credentials"}]}
120
+ ```
121
+
122
+ ### Starting a user session
123
+
124
+ Once the cobranded session is active a number of API endpoints will work however most of the interesting ones require you to register or login under a user account. It is within these accounts that you can add the user's bank accounts and whatnot to aggregate their financial data. There are 3 methods offered to allow you to #register_user, #login_user, or do either #login_or_register_user. After executing any of these the user session will be started and the user's session token will be cached in the YodleeApi instance and used on subsequent calls to api endpoints. As with all api calls if the call was not successful you'll need to look at the body of the response to determine what went wrong.
125
+
126
+ ### Registering a new user
127
+
128
+ ```
129
+ pry(main)> response = yodlee_api.register_user 'my-username', 'my-password123', 'my-email@my-domain.com'
130
+ pry(main)> yodlee_api.user_session_token
131
+ => "12162013_1:69761d51a4010e6382ccb49b854513dbccad0f835a873d37884b68826acefaa5b8d41b634f4cc83d97d86e7df861f70860a4e4d8a3f08d5b5440eae504af5f19"
132
+ ```
133
+
134
+ ### Login existing user
135
+
136
+ ```
137
+ pry(main)> response = yodlee_api.user_login 'my-username', 'my-password123'
138
+ pry(main)> yodlee_api.user_session_token
139
+ => "12162013_1:69761d51a4010e6382ccb49b854513dbccad0f835a873d37884b68826acefaa5b8d41b634f4cc83d97d86e7df861f70860a4e4d8a3f08d5b5440eae504af5f19"
140
+ ```
141
+
142
+ ### Convenience for doing both
143
+
144
+ In case you have a situation where you don't know if the user is already registered there is #login_or_register_user
145
+
146
+ ```
147
+ pry(main)> response = yodlee_api.login_or_register_user 'my-username', 'my-password123', 'my-email@my-domain.com'
148
+ pry(main)> yodlee_api.user_session_token
149
+ => "12162013_1:69761d51a4010e6382ccb49b854513dbccad0f835a873d37884b68826acefaa5b8d41b634f4cc83d97d86e7df861f70860a4e4d8a3f08d5b5440eae504af5f19"
150
+ ```
151
+ ### other API methods
152
+
153
+ TODO
154
+
155
+ ## Why the rename from Yodlicious?
156
+
157
+ Rubygems.org's search apparently only indexes the gem name not the description or summary. This meant that if you searched for Yodlee in there Yodlicous didn't show up. Now it does.
158
+
159
+ ## Contributing
160
+
161
+ 1. Fork it ( https://github.com/liftforward/yodlee-icious/fork )
162
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
163
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
164
+ 4. Push to the branch (`git push origin my-new-feature`)
165
+ 5. Create a new Pull Request
166
+
167
+ ### Running the integration suite
168
+
169
+ To run the Yodlee-icious integration tests you'll need an approved yodlee account. This is more than the one offered here [https://devnow.yodlee.com/user/register]. (Some of the integration suite will work against the devnow APIs but not all. On my todo list is to separate them out to make testing easier.) The integration suite expects these values to be set in the following environment variables:
170
+
171
+ ```
172
+ YODLEE_BASE_URL="https://consolidatedsdk.yodlee.com/yodsoap/srest/my-cobranded-path/v1.0"
173
+ YODLEE_COBRANDED_USERNAME="my-cobranded-user"
174
+ YODLEE_COBRANDED_PASSWORD="my-cobranded-password"
175
+ YODLEEICIOUS_PROXY_URL="https://my-proxy-server-on-the-whitelist:my=proxy-port/"
176
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,14 @@
1
+
2
+
3
+ module YodleeWrap
4
+ class Config
5
+ class << self
6
+ attr_accessor :cobranded_username, :cobrand_name, :cobranded_password,
7
+ :proxy_url, :logger, :webhook_endpoint
8
+ end
9
+
10
+ self.logger = Logger.new(STDOUT)
11
+ self.logger.level = Logger::WARN
12
+
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ module YodleeWrap
2
+ class ParameterTranslator
3
+ def site_login_form_to_add_site_account_params site_login_form
4
+
5
+ params = { "credentialFields.enclosedType" => "com.yodlee.common.FieldInfoSingle" }
6
+
7
+ i = 0
8
+ site_login_form['componentList'].each { |field|
9
+ # puts "field=#{field}"
10
+ params["credentialFields[#{i}].displayName"] = field['displayName']
11
+ params["credentialFields[#{i}].fieldType.typeName"] = field['fieldType']['typeName']
12
+ params["credentialFields[#{i}].helpText"] = field['helpText']
13
+ params["credentialFields[#{i}].maxlength"] = field['maxlength']
14
+ params["credentialFields[#{i}].name"] = field['name']
15
+ params["credentialFields[#{i}].size"] = field['size']
16
+ params["credentialFields[#{i}].value"] = field['value']
17
+ params["credentialFields[#{i}].valueIdentifier"] = field['valueIdentifier']
18
+ params["credentialFields[#{i}].valueMask"] = field['valueMask']
19
+ params["credentialFields[#{i}].isEditable"] = field['isEditable']
20
+ params["credentialFields[#{i}].value"] = field['fieldValue']
21
+
22
+ i += 1
23
+ }
24
+ params
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ module YodleeWrap
2
+ class Response
3
+ attr_accessor :body, :status, :error_code, :error_message
4
+
5
+ def initialize(body, status)
6
+ @body = body
7
+ @status = status
8
+ @error_code = body.fetch('errorCode') if fail?
9
+ @error_message = body.fetch('errorMessage') if fail?
10
+ end
11
+
12
+ def success?
13
+ !fail?
14
+ end
15
+
16
+ def fail?
17
+ body.is_a?(Hash) && !(body.fetch('errorCode', nil)).nil?
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module YodleeWrap
2
+ VERSION = "0.0.0"
3
+ end
@@ -0,0 +1,183 @@
1
+ require 'json'
2
+
3
+ module YodleeWrap
4
+ class YodleeApi
5
+ attr_reader :base_url, :cobranded_username, :cobranded_password, :proxy_url,
6
+ :logger, :cobranded_auth, :user_auth, :cobrand_name, :webhook_endpoint
7
+
8
+ def initialize(config = {})
9
+ configure(config)
10
+ end
11
+
12
+ def configure(config = {})
13
+ validate(config)
14
+ @cobrand_name = config[:cobrand_name] || YodleeWrap::Config.cobrand_name || 'restserver'
15
+ @cobranded_username = config[:cobranded_username] || YodleeWrap::Config.cobranded_username
16
+ @cobranded_password = config[:cobranded_password] || YodleeWrap::Config.cobranded_password
17
+ @webhook_endpoint = config[:webhook_endpoint] || YodleeWrap::Config.webhook_endpoint
18
+ @logger = config[:logger] || YodleeWrap::Config.logger
19
+
20
+ info_log "YodleeApi configured with base_url=#{base_url} cobranded_username=#{cobranded_username} logger=#{logger}"
21
+ end
22
+
23
+ def validate(config)
24
+ [:cobranded_username, :cobranded_password, :logger].each do |key|
25
+ if config.key?(key) && config[key].nil?
26
+ fail 'Invalid config provided to YodleeApi. Values may not be nil/blank.'
27
+ end
28
+ end
29
+ end
30
+
31
+ def cobranded_login
32
+ params = {
33
+ cobrand: {
34
+ cobrandLogin: cobranded_username,
35
+ cobrandPassword: cobranded_password,
36
+ locale: "en_US"
37
+ }
38
+ }
39
+ response = execute_api('/v1/cobrand/login', params)
40
+
41
+ @cobranded_auth = response.success? ? response.body : nil
42
+
43
+ response
44
+ end
45
+
46
+ def user_params(username, password)
47
+ {
48
+ user: {
49
+ loginName: username,
50
+ password: password,
51
+ locale: 'en_US'
52
+ }
53
+ }
54
+ end
55
+
56
+ def user_login(username:, password:)
57
+ params = user_params(username, password)
58
+ response = cobranded_session_execute_api('/v1/user/login', params)
59
+ @user_auth = response.success? ? response.body : nil
60
+ response
61
+ end
62
+
63
+ def register_user(username:, password:, options: {}, subscribe: true)
64
+ params = user_params(username, password).merge(options)
65
+ response = cobranded_session_execute_api('/v1/user/register', params)
66
+ @user_auth = response.success? ? response.body : nil
67
+ subscribe_user_to_refresh if response.success? && subscribe
68
+ response
69
+ end
70
+
71
+ # subscribe user to webhook refresh notifications
72
+ def subscribe_user_to_refresh
73
+ params = {
74
+ event: {
75
+ callbackUrl: webhookEndpoint
76
+ }
77
+ }
78
+ user_session_execute_api('v1/cobrand/config/notifications/events/REFRESH', params)
79
+ end
80
+
81
+ def unregister_user
82
+ response = user_session_execute_api('v1/user/unregister')
83
+ @user_auth = nil if response.success?
84
+ end
85
+
86
+ def logout_user
87
+ user_session_execute_api('/v1/user/logout')
88
+ end
89
+
90
+ def login_or_register_user(username:, password:, subscribe: true)
91
+ info_log "Attempting to log in #{username}"
92
+ response = user_login(username: username, password: password)
93
+
94
+ # TODO: look into what other errors could occur here
95
+ if response.fail? && response.error_code == 'Y002'
96
+ info_log "Invalid credentials for #{username}. Attempting to register"
97
+ response = register_user(username: username, password: password, subscribe: subscribe)
98
+ else
99
+ info_log response.error_message
100
+ end
101
+
102
+ @user_auth = response.success? ? response.body : nil
103
+
104
+ response
105
+ end
106
+
107
+ def get_provider_details(provider_id)
108
+ user_session_execute_api("/v1/providers/#{provider_id}")
109
+ end
110
+
111
+ def add_provider_account(provider_id, provider_params)
112
+ user_session_execute_api("v1/providers/#{provider_id}", provider_params)
113
+ end
114
+
115
+ def delete_provider_account(provider_account_id)
116
+ user_session_execute_api("v1/providers/providerAccounts/#{provider_account_id}")
117
+ end
118
+
119
+ # After an account has been added, use the returned provider_account_id
120
+ # to get updates about the provider account.
121
+ def get_provider_account_status(provider_account_id)
122
+ user_session_execute_api("v1/providers/#{provider_account_id}")
123
+ end
124
+
125
+ def update_provider_account(provider_account_id, provider_params)
126
+ user_session_execute_api("v1/providers/providerAccounts?providerAccountIds=#{provider_account_id}", provider_params)
127
+ end
128
+
129
+ def cobranded_session_execute_api(url, params = {})
130
+
131
+ execute_api(url, params, cobranded_auth_header)
132
+ end
133
+
134
+ def user_session_execute_api(url, params = {})
135
+
136
+ execute_api(url, params, user_auth_header)
137
+ end
138
+
139
+ def cobranded_auth_header
140
+ "cobSession=#{cobranded_session_token}"
141
+ end
142
+
143
+ def user_auth_header
144
+ cobranded_auth_header + "userSession=#{user_session_token}"
145
+ end
146
+
147
+ def execute_api(url, params, auth_header = "")
148
+ debug_log "calling #{url} with #{params}"
149
+ ssl_opts = { verify: false }
150
+ connection = Faraday.new(url: base_url, ssl: ssl_opts, request: { proxy: [] })
151
+ response = connection.post do |request|
152
+ request.url "#{base_url}#{url}"
153
+ request.headers['Content-Type'] = 'application/json'
154
+ request.headers['Authorization'] = auth_header
155
+ request.body = params.to_json
156
+ end
157
+ debug_log "response=#{response.status} success?=#{response.success?} body=#{response.body}"
158
+ Response.new(JSON.parse(response.body), response.status)
159
+ end
160
+
161
+ def cobranded_session_token
162
+ return nil if cobranded_auth.nil?
163
+ cobranded_auth.fetch('session', {}).fetch('cobSession', nil)
164
+ end
165
+
166
+ def user_session_token
167
+ return nil if user_auth.nil?
168
+ user_auth.fetch('session', {}).fetch('userSession', nil)
169
+ end
170
+
171
+ def debug_log(msg)
172
+ logger.debug(msg)
173
+ end
174
+
175
+ def info_log(msg)
176
+ logger.info(msg)
177
+ end
178
+
179
+ def base_url
180
+ "https://developer.api.yodlee.com/ysl/#{cobrand_name}"
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'logger'
3
+ require 'faraday'
4
+ require 'socksify'
5
+ require 'socksify/http'
6
+
7
+ require File.dirname(__FILE__) + "/yodlee_wrap/version"
8
+ require File.dirname(__FILE__) + "/yodlee_wrap/config"
9
+ require File.dirname(__FILE__) + "/yodlee_wrap/parameter_translator"
10
+ require File.dirname(__FILE__) + "/yodlee_wrap/response"
11
+ require File.dirname(__FILE__) + "/yodlee_wrap/yodlee_api"
12
+
13
+ class Faraday::Adapter::NetHttp
14
+ def net_http_connection(env)
15
+ if !(proxy = env[:request][:proxy]).empty?
16
+ if proxy[:socks]
17
+ # TCPSocket.socks_username = proxy[:user] if proxy[:user]
18
+ # TCPSocket.socks_password = proxy[:password] if proxy[:password]
19
+ Net::HTTP::SOCKSProxy(proxy[:uri].host, proxy[:uri].port)
20
+ else
21
+ Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:uri].user, proxy[:uri].password)
22
+ end
23
+ else
24
+ Net::HTTP
25
+ end.new(env[:url].host, env[:url].port)
26
+ end
27
+ end
data/log/.gitkeep ADDED
File without changes