[add] added maximum client and demo client protection

- default demo clients can no longer be modified/deleted when in demo mode
 - increased default demo reset to 60 minutes
This commit is contained in:
2021-02-25 12:52:23 -05:00
parent 472ae4c90f
commit 5868377210
7 changed files with 60 additions and 7 deletions

33
api.yml
View File

@@ -1,11 +1,34 @@
openapi: "3.0.0"
info:
description: "Simple dynDNS via Rest-API."
description: "Simple dynDNS via Rest-API.
The demo database will reset every **60** minutes. A maximum of 250 clients can exist in the demo database.
The following default clients and api keys can be used:
| client name | api key |
|--------------|------------------------------------------------------------------------------------------|
| admin | `zW3If4s5.41a7c846.23b142e6451df545d5034ca8f6050b80ff3e9689f20d5e45d72d160fa7e1cf32` |
| read_client | `zW3If4s5.28aef5cb.d502cb94ba0802c6363f95ecb3a70de7e2e4b889779e435b7c033f2c72ed4f20` |
| write_client | `zW3If4s5.3d6129cc.48d41d2a28b16a9a274d3f407026aee2b82cddbb3c11a5496ffe329c78e5d54b` |
In `demo-mode` it is not possible to call `POST /admin/client`, `PUT /admin/client` or `DELETE /admin/clients/{client_name}` for any of the above default clients. Any newly created client can be freely modified.
***Note**: the X-API-Key value entered when using Authorize takes precedence over values entered in the X-API-Key parameters field.
Since the X-API-Key parameter field is flagged as required a simple space (or any other character) will still be needed for executing the request here.*
"
version: "1.0"
title: "rynDNS"
servers:
- url: "https://api.pdev.dev/rynDNS/v1"
- url: "https://demo.api.pdev.dev/rynDNS"
description: ""
security:
@@ -49,6 +72,8 @@ paths:
description: "Invalid input"
"406":
description: "Not Acceptable - Can not remove last admin account permissions"
"429":
description: "Too many clients - Maximum client count reached"
put:
tags:
- "admin"
@@ -356,5 +381,5 @@ components:
example: "115.16.0.99"
pattern: "^(((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(.(?!$)|$)){4})?$"
externalDocs:
description: "Source"
url: "https://git.pdev.dev"
description: "<rynDNS source code>"
url: "https://git.pdev.dev/pdev/ryndns"

View File

@@ -9,6 +9,7 @@ class ClientsController < ApplicationController
before_action :authorize_perm_w, only: %i[update_ipv4 destroy_ipv4]
before_action :authorize_perm_x, only: %i[create update index show destroy]
before_action :client_authorized, except: [:show_public_ipv4]
before_action :demo, only: %i[create update destroy] if ENV['RAILS_API_DEMO']
# URL Methods
# POST /admin/client
@@ -22,6 +23,7 @@ class ClientsController < ApplicationController
# create new client or update existing
if client.nil?
client ||= Client.new_client(client_params)
return head(429) if client.nil? # reached max client count
else
# return 406 if request is trying to remove perm_x from last admin account to prevent lockout
# TODO: move this into the model (update)
@@ -217,4 +219,11 @@ class ClientsController < ApplicationController
def client_authorized
return head(403) unless @authorized
end
# TODO: put this into a demo environment
def demo
demo_clients = %w[admin read_client write_client]
request_params = params.key?(:name) ? params[:name] : ''
return head(406) if demo_clients.include? request_params
end
end

View File

@@ -3,6 +3,8 @@
class Client < ApplicationRecord
def self.new_client(params)
return nil if count >= RynDNS::Application::MAX_CLIENTS
perm_string = params[:permission] || 'w' # create write client by default
perm_rwx = Client.parse_perm_string(perm_string)
@@ -28,7 +30,7 @@ class Client < ApplicationRecord
def gen_api_key
api_key = SecureRandom.hex(32)
self.api_key = api_key
"#{RynDNS::Application::API_KEY_PREFIX}.#{self.name_id}.#{api_key}"
"#{RynDNS::Application::API_KEY_PREFIX}.#{name_id}.#{api_key}"
end
def api_key

View File

@@ -58,5 +58,6 @@ module RynDNS
puts "WARNING: Please modify api_key -> #{API_KEY_PREFIX}.########.############"
end
API_KEY_HEADER = ENV['RAILS_API_KEY_HEADER'] || 'X-API-Key'
MAX_CLIENTS = ENV['RAILS_MAX_CLIENTS'] || 250
end
end

View File

@@ -10,6 +10,8 @@ services:
environment:
# set to run app in subdirectory
RAILS_RELATIVE_URL_ROOT: /rynDNS
# set maximum number of clients in db
#RAILS_MAX_CLIENTS: 250
# set custom api key prefix
#API_KEY_PREFIX: zW3If4s5
# set custom header name for api key
@@ -19,7 +21,7 @@ services:
# set app to run as demo
#RAILS_API_DEMO: 1
# set cycle to reset demo data
#RAILS_DEMO_RESET: 300
#RAILS_DEMO_RESET: 60m
restart: always
image: ryndns
container_name: ryndns

View File

@@ -7,7 +7,7 @@ prefix_file="${API_PREFIX_FILE:-/app/data/api_prefix}"
db_file="${RAILS_DB_PATH:-/app/data/rynDNS.sqlite3}"
default_admin_file="${API_DEFAULT_KEY_FILE:-/app/data/api_default_admin}"
rails_bin="${RAILS_BINARY:-/app/bin/rails}"
demo_cycle="${RAILS_DEMO_RESET:-300s}"
demo_cycle="${RAILS_DEMO_RESET:-60m}"
demo_prefix="zW3If4s5"
seed_default_key_text="Created default admin with api_key" # for grep'ing the default admin key

View File

@@ -160,6 +160,20 @@ RSpec.describe 'Clients', type: :request do
expect(response).to have_http_status(200)
end
end
context 'when sending a valid request to add another client above the MAX_CLIENTS limit' do
before do
clients_to_create = RynDNS::Application::MAX_CLIENTS - Client.count
create_list(:client, clients_to_create)
post '/admin/client', params: { name: 'extra_user' }, headers: api_key_header(admin_client)
end
it 'does not add another client and returns status code 429' do
expect(Client.count).to eq RynDNS::Application::MAX_CLIENTS
expect(response.body).to be_empty
expect(response).to have_http_status(429)
end
end
end
describe 'PUT /admin/client' do