ssrfs-up-v2 0.21.2
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.
- checksums.yaml +7 -0
- data/lib/openapi_client/lib/openapi_client/api/default_api.rb +88 -0
- data/lib/openapi_client/lib/openapi_client/api_client.rb +426 -0
- data/lib/openapi_client/lib/openapi_client/api_error.rb +57 -0
- data/lib/openapi_client/lib/openapi_client/configuration.rb +306 -0
- data/lib/openapi_client/lib/openapi_client/models/content_type.rb +40 -0
- data/lib/openapi_client/lib/openapi_client/models/method.rb +40 -0
- data/lib/openapi_client/lib/openapi_client/models/redirect.rb +243 -0
- data/lib/openapi_client/lib/openapi_client/models/request.rb +381 -0
- data/lib/openapi_client/lib/openapi_client/models/response.rb +299 -0
- data/lib/openapi_client/lib/openapi_client/models/response_error.rb +225 -0
- data/lib/openapi_client/lib/openapi_client/models/response_success.rb +276 -0
- data/lib/openapi_client/lib/openapi_client/version.rb +15 -0
- data/lib/openapi_client/lib/openapi_client.rb +47 -0
- data/lib/ssrfs-up/version.rb +3 -0
- data/lib/ssrfs-up.rb +201 -0
- metadata +156 -0
data/lib/ssrfs-up.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
require "aws-sdk-lambda"
|
2
|
+
require "uri"
|
3
|
+
require "ssrfs-up/version"
|
4
|
+
require "ostruct"
|
5
|
+
require "ssrf_filter"
|
6
|
+
require "cgi"
|
7
|
+
|
8
|
+
# Common files
|
9
|
+
require "openapi_client/lib/openapi_client/api_client"
|
10
|
+
require "openapi_client/lib/openapi_client/api_error"
|
11
|
+
require "openapi_client/lib/openapi_client/version"
|
12
|
+
require "openapi_client/lib/openapi_client/configuration"
|
13
|
+
|
14
|
+
# Models
|
15
|
+
require "openapi_client/lib/openapi_client/models/content_type"
|
16
|
+
require "openapi_client/lib/openapi_client/models/method"
|
17
|
+
require "openapi_client/lib/openapi_client/models/redirect"
|
18
|
+
require "openapi_client/lib/openapi_client/models/request"
|
19
|
+
require "openapi_client/lib/openapi_client/models/response"
|
20
|
+
require "openapi_client/lib/openapi_client/models/response_error"
|
21
|
+
require "openapi_client/lib/openapi_client/models/response_success"
|
22
|
+
|
23
|
+
# APIs
|
24
|
+
require "openapi_client/lib/openapi_client/api/default_api"
|
25
|
+
##
|
26
|
+
# This module contains the AWS lambda client and helper methods to easily
|
27
|
+
# make requests to it. All methods take a hostname or URI and a hash or options
|
28
|
+
# for the request.
|
29
|
+
module SSRFsUp
|
30
|
+
class Configuration
|
31
|
+
attr_accessor :func_name, :invoke_type, :log_type, :region, :test, :proxy
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@func_name = "arn:aws:lambda:us-west-2:871040364337:function:sec-czi-sec-ssrfs-up:sec-czi-sec-ssrfs-up"
|
35
|
+
@invoke_type = "RequestResponse"
|
36
|
+
@log_type = "None"
|
37
|
+
@region = "us-west-2"
|
38
|
+
@test = false
|
39
|
+
@proxy = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
attr_accessor :config, :client
|
45
|
+
|
46
|
+
# These methods take a string like "www.google.com" or "https://google.com" and parse
|
47
|
+
# the respective parameters from the string to make the request. If only a hostname
|
48
|
+
# is provided, the default options are applied. A hash of options can also be
|
49
|
+
# supplied to configure the request. The set of options can be found at
|
50
|
+
# https://github.com/chanzuckerberg/SSRFs-Up/blob/0e18fd30bee3f2b99ff4bc512cb967b83e8d9dcb/openapi.yaml#L97-L119
|
51
|
+
def do(method, host, opts = {})
|
52
|
+
case method.downcase
|
53
|
+
when "get"
|
54
|
+
get(host, opts)
|
55
|
+
when "put"
|
56
|
+
put(host, opts)
|
57
|
+
when "post"
|
58
|
+
post(host, opts)
|
59
|
+
when "patch"
|
60
|
+
patch(host, opts)
|
61
|
+
when "delete"
|
62
|
+
delete(host, opts)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# convenience method for making a GET request with do.
|
67
|
+
def get(host, opts = {})
|
68
|
+
opts[:method] = "GET"
|
69
|
+
invoke(host, opts)
|
70
|
+
end
|
71
|
+
|
72
|
+
# convenience method for making a PUT request with do.
|
73
|
+
def put(host, opts = {})
|
74
|
+
opts[:method] = "PUT"
|
75
|
+
invoke(host, opts)
|
76
|
+
end
|
77
|
+
|
78
|
+
# convenience method for making a POST request with do.
|
79
|
+
def post(host, opts = {})
|
80
|
+
opts[:method] = "POST"
|
81
|
+
invoke(host, opts)
|
82
|
+
end
|
83
|
+
|
84
|
+
# convenience method for making a patch request with do.
|
85
|
+
def patch(host, opts = {})
|
86
|
+
opts[:method] = "PATCH"
|
87
|
+
invoke(host, opts)
|
88
|
+
end
|
89
|
+
|
90
|
+
# convenience method for making a DELETE request with do.
|
91
|
+
def delete(host, opts = {})
|
92
|
+
opts[:method] = "DELETE"
|
93
|
+
invoke(host, opts)
|
94
|
+
end
|
95
|
+
|
96
|
+
# takes an ambiguous string or URI and sets the appropriate options based
|
97
|
+
# on if it can be parsed as URI object. If it can't, then the string is assumed
|
98
|
+
# to be a hostname only.
|
99
|
+
def parseAsUri(uri = "")
|
100
|
+
uri = uri.to_s
|
101
|
+
opts = { :host => uri.split("/")[0].split("?")[0].split("#")[0] }
|
102
|
+
u = URI(uri)
|
103
|
+
|
104
|
+
# if the scheme was present, we can parse most of the options from the URI.
|
105
|
+
# otherwise, we can assume the URI was an actual hostname
|
106
|
+
unless u.scheme.nil?
|
107
|
+
opts[:secure] = !(u.scheme == "http")
|
108
|
+
opts[:host] = u.host
|
109
|
+
opts[:path] = u.path unless u.path == ""
|
110
|
+
opts[:params] = CGI.parse(u.query) unless u.query.nil?
|
111
|
+
end
|
112
|
+
opts
|
113
|
+
end
|
114
|
+
|
115
|
+
# converts a hash of options to a valid OpenapiClient Request so that it
|
116
|
+
# can be properly consumed by the lambda.
|
117
|
+
def toOpenAPIClient(opts = {})
|
118
|
+
OpenapiClient::Request.new(opts).to_hash
|
119
|
+
end
|
120
|
+
|
121
|
+
# configures the SSRFsUp module and recreates the AWS Lambda Client from
|
122
|
+
# the updated configuration.
|
123
|
+
def configure
|
124
|
+
yield(configuration)
|
125
|
+
@client = Aws::Lambda::Client.new({ region: configuration.region, stub_responses: configuration.test })
|
126
|
+
end
|
127
|
+
|
128
|
+
def configuration
|
129
|
+
@config ||= Configuration.new
|
130
|
+
end
|
131
|
+
|
132
|
+
def client
|
133
|
+
@client ||= Aws::Lambda::Client.new(region: configuration.region)
|
134
|
+
end
|
135
|
+
|
136
|
+
def fast_check(host, opts)
|
137
|
+
scheme = opts[:secure] ? "https://" : "http://"
|
138
|
+
path = opts[:path].nil? ? "" : opts[:path]
|
139
|
+
params = opts[:params].nil? ? "" : "?" + URI.encode_www_form(opts[:params])
|
140
|
+
url = scheme + host + path + params
|
141
|
+
|
142
|
+
filter_opts = { :max_redirects => opts[:redirect].nil? ? 3 : opts[:redirect] }
|
143
|
+
filter_opts[:params] = opts[:params] unless opts[:params].nil?
|
144
|
+
filter_opts[:body] = opts[:body] unless opts[:body].nil?
|
145
|
+
filter_opts[:headers] = opts[:headers] unless opts[:headers].nil?
|
146
|
+
|
147
|
+
begin
|
148
|
+
case opts[:method].downcase
|
149
|
+
when "get"
|
150
|
+
resp = SsrfFilter.get(url, filter_opts)
|
151
|
+
when "put"
|
152
|
+
resp = SsrfFilter.put(url, filter_opts)
|
153
|
+
when "post"
|
154
|
+
resp = SsrfFilter.post(url, filter_opts)
|
155
|
+
when "delete"
|
156
|
+
resp = SsrfFilter.delete(url, filter_opts)
|
157
|
+
when "patch"
|
158
|
+
return { status_code: 404, status_text: "Unsupported method", body: "Cannot use patch with fast path." }
|
159
|
+
end
|
160
|
+
|
161
|
+
{ status_code: resp.code.to_i, status_text: resp.message, body: resp.body }
|
162
|
+
rescue SsrfFilter::PrivateIPAddress => exception
|
163
|
+
{ status_code: 404, status_text: "Invalid destination", body: exception.to_s }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# invokes the lambda with the provided arguments. It handles all lambda
|
168
|
+
# related errors so developers should assume the data they receive back is straight
|
169
|
+
# from the server they are speaking to.
|
170
|
+
def invoke(host = nil, opts = {})
|
171
|
+
opts = opts.merge(parseAsUri(host))
|
172
|
+
if (!opts[:proxy].nil? && !opts[:proxy]) || !configuration.proxy
|
173
|
+
OpenStruct.new(fast_check(opts[:host], opts))
|
174
|
+
else
|
175
|
+
begin
|
176
|
+
resp = client.invoke({
|
177
|
+
function_name: configuration.func_name,
|
178
|
+
invocation_type: configuration.invoke_type,
|
179
|
+
log_type: configuration.log_type,
|
180
|
+
payload: payload(opts),
|
181
|
+
})
|
182
|
+
|
183
|
+
if resp["status_code"] == 200
|
184
|
+
OpenStruct.new(JSON.parse(resp&.payload&.string))
|
185
|
+
else
|
186
|
+
OpenStruct.new({ body: "", status_code: resp[status_code], status_text: "500 Error with proxy" })
|
187
|
+
end
|
188
|
+
rescue StandardError => e
|
189
|
+
# fall back to local check if the lambda wasn't reachable.
|
190
|
+
OpenStruct.new(fast_check(opts[:host], opts))
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# payload builds an API client Request object with the proper defaults and
|
196
|
+
# returns its JSON serialization.
|
197
|
+
def payload(opts = {})
|
198
|
+
toOpenAPIClient(opts).to_json
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ssrfs-up-v2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.21.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jake Heath
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-08-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk-lambda
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: ssrf_filter
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: pry
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rake
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '3.6'
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 3.6.0
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - "~>"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '3.6'
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: 3.6.0
|
109
|
+
description: A gem that simplifies connecting to out AWS Lambda used to proxy requests.
|
110
|
+
Make your third-party requests secure by default.
|
111
|
+
email:
|
112
|
+
- jheath@chanzuckerberg.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- lib/openapi_client/lib/openapi_client.rb
|
118
|
+
- lib/openapi_client/lib/openapi_client/api/default_api.rb
|
119
|
+
- lib/openapi_client/lib/openapi_client/api_client.rb
|
120
|
+
- lib/openapi_client/lib/openapi_client/api_error.rb
|
121
|
+
- lib/openapi_client/lib/openapi_client/configuration.rb
|
122
|
+
- lib/openapi_client/lib/openapi_client/models/content_type.rb
|
123
|
+
- lib/openapi_client/lib/openapi_client/models/method.rb
|
124
|
+
- lib/openapi_client/lib/openapi_client/models/redirect.rb
|
125
|
+
- lib/openapi_client/lib/openapi_client/models/request.rb
|
126
|
+
- lib/openapi_client/lib/openapi_client/models/response.rb
|
127
|
+
- lib/openapi_client/lib/openapi_client/models/response_error.rb
|
128
|
+
- lib/openapi_client/lib/openapi_client/models/response_success.rb
|
129
|
+
- lib/openapi_client/lib/openapi_client/version.rb
|
130
|
+
- lib/ssrfs-up.rb
|
131
|
+
- lib/ssrfs-up/version.rb
|
132
|
+
homepage: https://github.com/chanzuckerberg/ssrf-proxy
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata:
|
136
|
+
homepage_uri: https://github.com/chanzuckerberg/ssrf-proxy
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 2.3.0
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubygems_version: 3.1.6
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Proxy all requests to avoid SSRF.
|
156
|
+
test_files: []
|