Rate limiting & refactor

master
E. Almqvist 3 years ago
parent 3035a3ea3d
commit ce05aed461
  1. 4
      src/TODO.md
  2. 43
      src/app.rb
  3. 17
      src/const.rb
  4. 9
      src/lib/db_models.rb
  5. 8
      src/routes/auction.rb
  6. 2
      src/views/admin/index.slim
  7. 4
      src/views/auction/index.slim
  8. 1
      src/views/auction/view.slim
  9. 9
      src/views/stylesheets/style.sass

@ -1,6 +1,6 @@
# TODO
- Post editing & deleting
- User reviews
- Ratelimiting
- User reviews (+rep / -rep)
- Yardoc 50%
- Film

@ -32,18 +32,7 @@ end
enable :sessions
db_init
before do
route_auth_needed = request.path_info.start_with?(*AUTH_ROUTES)
if !is_logged_in && route_auth_needed then
session[:ret] = request.fullpath # TODO: return the user to the previous route
session[:status] = 403
flash[:error] = AUTH_ERRORS[:needed]
redirect "/login"
elsif route_auth_needed && get_current_user.banned?
banned
end
end
RATE_LIMITS ||= Hash.new(Hash.new(0))
not_found do
serve :"404"
@ -68,6 +57,36 @@ def error(ret=back)
auth_denied "Internal server error.", 500, ret
end
def ratelimit(delta_time, ret="/")
auth_denied "Doing that a bit too fast... Please try again in #{delta_time} seconds.", 429, ret
end
before do
# Ratelimiting
# check if route contains any of the protected ones
# and if it is a POST request (dont care about GETs)
if request.path_info.start_with?(*RATE_LIMIT_ROUTES_ALL) and request.request_method == "POST" then
RATE_LIMIT_ROUTES.each do |t, cfg|
if request.path_info.start_with?(*cfg[:routes]) then
dt = Time.now.to_i - RATE_LIMITS[t][request.ip]
ratelimit(dt) unless dt > cfg[:time] # send a rate limit response if rate limited
RATE_LIMITS[t][request.ip] = Time.now.to_i
end
end
end
# Authentication check
route_auth_needed = request.path_info.start_with?(*AUTH_ROUTES)
if !is_logged_in && route_auth_needed then
session[:ret] = request.fullpath # TODO: return the user to the previous route
session[:status] = 403
flash[:error] = AUTH_ERRORS[:needed]
redirect "/login"
elsif route_auth_needed && get_current_user.banned?
banned
end
end
# Routes
get "/style.css" do
sass :"stylesheets/style", style: :compressed

@ -78,7 +78,22 @@ TIME_FORMATS = {
s: 1
}
# Routes that needs auth
AUTH_ROUTES = %w[/settings /auction /user /admin]
# Rate limits in seconds for each route category
RATE_LIMIT_ROUTES = {
user: {
routes: %w[/user /settings /register /login /logout],
time: 1
},
auction: {
routes: %w[/auctions],
time: 1
}
}
RATE_LIMIT_ROUTES_ALL = [] # precompile all of the protected routes
RATE_LIMIT_ROUTES.each do |t, cfg|
RATE_LIMIT_ROUTES_ALL += cfg[:routes]
end

@ -383,6 +383,15 @@ class Auction < EntityModel
Auction.update data, "id = ?", @id
end
def delete
FileUtils.rm_rf("./public/auctions/#{@id}") # delete all images
Auction.delete "id = ?", @id # delete the actual post entry
Auction_Category_relation.delete "auction_id = ?", @id
Image.delete "auction_id = ?", @id
Bid.delete "auction_id = ?", @id
end
def poster
User.find_by_id @user_id
end

@ -23,13 +23,12 @@ post "/auctions" do
init_price = params[:init_price].to_f
delta_time = params[:delta_time].to_i * 3600 # hours to seconds
images = params[:images]
# Min image count check
if images.nil? or images.length < AH_MIN_IMAGES then
flash[:error] = AUCTION_ERRORS[:imagecount]
redirect "/auctions/new"
end
#
# Create the auction
newid, resp = Auction.create user_id, title, description, init_price, delta_time
@ -91,12 +90,9 @@ get "/auctions/:id/delete" do
auth_denied unless auction.user_id == session[:userid] or get_current_user.admin?
# Delete everything related in the db
Auction.delete "id = ?", id
Auction_Category_relation.delete "auction_id = ?", id
Bid.delete "auction_id = ?", id
auction.delete
flash[:success] = "Removed post."
redirect "/auctions"
else
raise Sinatra::NotFound

@ -6,8 +6,6 @@ div
a.button href="#users" = "Users"
li
a.button href="#roles" = "Roles"
li
a.button href="#auctions" = "Auctions"
li
a.button href="#categories" = "Categories"

@ -5,7 +5,7 @@
.form-container
form action="/auctions" method="get"
label Title
input type="search" name="title" placeholder="ex: 'teapot'"
input type="search" name="title" placeholder="ex: 'teapot'" value="#{params[:title]}"
label Price range
.range-container
@ -25,7 +25,7 @@
option value="#{category.id}" selected=("selected" if params[:categories] and params[:categories].include?(category.id.to_s)) style="color: #{category.color};" = "#{category.name}"
input type="submit" value="Search"
a.button href="/auctions" = "Clear Filters"
a.button href="/auctions" = "Clear Filters"
article.post-container.card
h2 Results

@ -20,6 +20,7 @@
h2
span
| #{auction.title}
h3
- if auction.user_id == session_user.id or session_user.admin?
a.inlbutton href="/auctions/#{auction.id}/edit"
| [Edit]

@ -474,7 +474,7 @@ ul.list-container
display: flex
flex-direction: row
justify-content: center
height: inherit
height: 90%
max-width: 70rem
a.button
@ -482,10 +482,14 @@ ul.list-container
border-radius: $border_radius
aside.card
display: flex
//justify-content: center
flex-direction: column
width: 20rem
margin-right: 4rem
margin-top: 4rem
.form-container
background: $bg_alt_clr
padding: 8px
form
padding: 0
width: inherit
@ -544,7 +548,6 @@ article.post-container
#auctions_new
display: grid
#auction-view
display: grid
max-width: 70rem

Loading…
Cancel
Save