Skip to content

Commit

Permalink
Update proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
hack3rvaillant committed Oct 29, 2024
1 parent 67ae08c commit 9cad4b3
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 99 deletions.
5 changes: 2 additions & 3 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ source "https://rubygems.org"

gem "jwt", "~> 2.9"
gem "sinatra", "~> 4.0"
gem "rackup", "~> 2.1"
gem "puma"


group :development, :test do
gem "rspec", "~> 3.13"
gem "rack-test", "~> 2.1"
gem "debug", ">= 1.0.0"
gem "webmock"
gem "dotenv"
gem "standardrb", "~> 1.0"
end

gem "rackup", "~> 2.1"
43 changes: 43 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ GEM
specs:
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.2)
base64 (0.2.0)
bigdecimal (3.1.8)
crack (1.0.0)
Expand All @@ -18,16 +19,24 @@ GEM
irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.7.4)
jwt (2.9.3)
base64
language_server-protocol (3.17.0.3)
lint_roller (1.1.0)
mustermann (3.0.3)
ruby2_keywords (~> 0.0.1)
nio4r (2.7.3)
parallel (1.26.3)
parser (3.3.5.0)
ast (~> 2.4.1)
racc
psych (5.1.2)
stringio
public_suffix (6.0.1)
puma (6.4.3)
nio4r (~> 2.0)
racc (1.8.1)
rack (3.1.8)
rack-protection (4.0.0)
base64 (>= 0.1.0)
Expand All @@ -39,8 +48,10 @@ GEM
rackup (2.1.0)
rack (>= 3)
webrick (~> 1.8)
rainbow (3.1.1)
rdoc (6.7.0)
psych (>= 4.0.0)
regexp_parser (2.9.2)
reline (0.5.10)
io-console (~> 0.5)
rexml (3.3.9)
Expand All @@ -57,15 +68,46 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.1)
rubocop (1.66.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0)
rubocop-ast (>= 1.32.2, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.32.3)
parser (>= 3.3.1.0)
rubocop-performance (1.22.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
sinatra (4.0.0)
mustermann (~> 3.0)
rack (>= 3.0.0, < 4)
rack-protection (= 4.0.0)
rack-session (>= 2.0.0, < 3)
tilt (~> 2.0)
standard (1.41.1)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.66.0)
standard-custom (~> 1.0.0)
standard-performance (~> 1.5)
standard-custom (1.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.50)
standard-performance (1.5.0)
lint_roller (~> 1.1)
rubocop-performance (~> 1.22.0)
standardrb (1.0.1)
standard
stringio (3.1.1)
tilt (2.4.0)
unicode-display_width (2.6.0)
webmock (3.24.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
Expand All @@ -85,6 +127,7 @@ DEPENDENCIES
rackup (~> 2.1)
rspec (~> 3.13)
sinatra (~> 4.0)
standardrb (~> 1.0)
webmock

BUNDLED WITH
Expand Down
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Proxy Server with JWT Authentication

This is a lightweight HTTP proxy server built using the Sinatra framework. It acts as a pass-through proxy, allowing requests to be forwarded to a specified target URL. Additionally, it provides JWT (JSON Web Token) authentication to secure requests.
This is a lightweight HTTP proxy server built using the Sinatra framework. It acts as a pass-through proxy, allowing requests to be forwarded to a specified target URL. Additionally, it provides JWT (JSON Web Token) authentication to secure requests.

## Features

- **CORS Support**: Handles CORS headers, allowing cross-origin requests.
- **JWT Authentication**: Verifies the presence and validity of the `x-bump-jwt-token` header to ensure requests are authorized.
- **Flexible HTTP Method Support**: Supports `GET`, `POST`, `PUT`, and `DELETE` methods for forwarding client requests to the target server.
- **Flexible HTTP Method Support**: Supports `GET`, `POST`, `PUT`,`PATCH`, and `DELETE` methods for forwarding client requests to the target server.
- **Automatic Request Forwarding**: Forwards requests to the specified target URL while preserving headers and request bodies.

## Getting Started
Expand Down Expand Up @@ -52,24 +52,24 @@ The server verifies the `x-bump-jwt-token` for every request. If the token is mi

The server provides the following endpoints for request forwarding:

- **GET** `/proxy?url=your-target-url`
- **POST** `/proxy?url=your-target-url`
- **PUT** `/proxy?url=your-target-url`
- **PATCH** `/proxy?url=your-target-url`
- **DELETE** `/proxy?url=your-target-url`
- **GET** `?url=your-target-url`
- **POST** `?url=your-target-url`
- **PUT** `?url=your-target-url`
- **PATCH** `?url=your-target-url`
- **DELETE** `?url=your-target-url`

Each endpoint forwards the request to the target URL specified in the query parameter.

### Example Requests

**GET request:**
```bash
curl -X GET "http://localhost:4567/proxy?url=https://jsonplaceholder.typicode.com/posts" -H "x-bump-jwt-token: YOUR_TOKEN"
curl -X GET "http://localhost:4567/?url=https://jsonplaceholder.typicode.com/posts" -H "x-bump-jwt-token: YOUR_TOKEN"
```

**POST request:**
```bash
curl -X POST "http://localhost:4567/proxy?url=https://jsonplaceholder.typicode.com/posts" \
curl -X POST "http://localhost:4567/?url=https://jsonplaceholder.typicode.com/posts" \
-H "Content-Type: application/json" \
-H "x-bump-jwt-token: YOUR_TOKEN" \
-d '{"title":"foo","body":"bar","userId":1}'
Expand All @@ -86,7 +86,7 @@ The server includes CORS headers for cross-origin access. Preflight OPTIONS requ

## License

This project is licensed under the MIT License.
This project is licensed under the MIT License.

## Contributing

Expand Down
4 changes: 2 additions & 2 deletions config.ru
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# config.ru

require './proxy_server' # Adjust the path if necessary
run Sinatra::Application
require "./proxy_server" # Adjust the path if necessary
run ProxyServer
10 changes: 5 additions & 5 deletions config/puma.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# config/puma.rb

workers Integer(ENV['WEB_CONCURRENCY'] || 2) # Number of worker processes
threads_count = Integer(ENV['MAX_THREADS'] || 5) # Max threads per worker
workers Integer(ENV["WEB_CONCURRENCY"] || 2) # Number of worker processes
threads_count = Integer(ENV["MAX_THREADS"] || 5) # Max threads per worker
threads threads_count, threads_count

preload_app!

# Define the rackup file
rackup 'config.ru' # Create this file next
port ENV['PORT'] || 4567
environment ENV['RACK_ENV'] || 'development'
rackup "config.ru" # Create this file next
port ENV["PORT"] || 4567
environment ENV["RACK_ENV"] || "development"

on_worker_boot do
# Worker specific setup for Rails 4.1+
Expand Down
82 changes: 44 additions & 38 deletions proxy_server.rb
Original file line number Diff line number Diff line change
@@ -1,99 +1,105 @@
require 'sinatra/base'
require 'net/http'
require 'uri'
require 'json'
require 'jwt'
require 'debug'
require "sinatra/base"
require "net/http"
require "uri"
require "json"
require "jwt"
require "debug"

class ProxyServer < Sinatra::Base

set :port, 4567

# Secret key for JWT verification
SECRET_KEY = 'your-secret-key'
SECRET_KEY = "your-secret-key"

# Handle CORS headers
before do
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE'],
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, x-bump-jwt-token'
headers "Access-Control-Allow-Origin" => "*",
"Access-Control-Allow-Methods" => ["OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE"],
"Access-Control-Allow-Headers" => "Content-Type, Authorization, x-bump-proxy-token, x-requested-with"
end

# Verify JWT token presence and signature
before do
token = request.env['HTTP_X_BUMP_JWT_TOKEN']
token = request.env["HTTP_X_BUMP_JWT_TOKEN"]

# Check if token is missing
if token.nil?
headers 'Content-Type' => 'application/json'
halt 401, { error: 'x-bump-jwt-token header is missing' }.to_json
headers "Content-Type" => "application/json"
halt 401, {error: "x-bump-jwt-token header is missing"}.to_json
end

# Verify JWT token
begin
JWT.decode(token, SECRET_KEY, true, { algorithm: 'HS256' })
JWT.decode(token, SECRET_KEY, true, {algorithm: "HS256"})
rescue JWT::DecodeError
halt 401, { error: 'Invalid token' }.to_json
halt 401, {error: "Invalid token"}.to_json
end
end

# OPTIONS request for preflight
options '*' do
options "*" do
200
end

helpers do
def forward_request(method)
target_url = params['url']
target_url = params["url"]
uri = URI.parse(target_url)

# Set up the request to the target server
target_request = case method
when 'GET' then Net::HTTP::Get.new(uri)
when 'POST' then Net::HTTP::Post.new(uri)
when 'PUT' then Net::HTTP::Put.new(uri)
when 'DELETE' then Net::HTTP::Delete.new(uri)
end
target_request =
case method
when "GET" then Net::HTTP::Get.new(uri)
when "POST" then Net::HTTP::Post.new(uri)
when "PUT" then Net::HTTP::Put.new(uri)
when "PATCH" then Net::HTTP::Patch.new(uri)
when "DELETE" then Net::HTTP::Delete.new(uri)
end

# Transfer relevant headers from the client to the target request
client_headers = request.env.select { |key, _| key.start_with?('HTTP_') }
client_headers = request.env.select { |key, _| key.start_with?("HTTP_") }
client_headers.each do |header, value|
formatted_header = header.sub('HTTP_', '').split('_').map(&:capitalize).join('-')
target_request[formatted_header] = value unless formatted_header == 'X-Bump-Jwt-Token'
formatted_header = header.sub("HTTP_", "").split("_").map(&:capitalize).join("-")
target_request[formatted_header] = value unless formatted_header == "X-Bump-Jwt-Token"
end

# Forward request body for POST and PUT methods
if %w[POST PUT].include?(method)
if %w[POST PUT PATCH].include?(method)
target_request.content_type = request.content_type
target_request.body = request.body.read
end

# Execute the request to the target server
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
response = http.request(target_request)

# Pass the target server response back to the client
puts response.read_body
status response.code
headers 'Content-Type' => response.content_type
headers "Content-Type" => response.content_type
body response.body
end
end
end

# Proxy endpoints
get '/proxy' do
forward_request('GET')
get "/" do
forward_request("GET")
end

post "/" do
forward_request("POST")
end

post '/proxy' do
forward_request('POST')
put "/" do
forward_request("PUT")
end

put '/proxy' do
forward_request('PUT')
patch "/" do
forward_request("PATCH")
end

delete '/proxy' do
forward_request('DELETE')
delete "/" do
forward_request("DELETE")
end
end
Loading

0 comments on commit 9cad4b3

Please sign in to comment.