[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:
33
api.yml
33
api.yml
@@ -1,11 +1,34 @@
|
|||||||
openapi: "3.0.0"
|
openapi: "3.0.0"
|
||||||
info:
|
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"
|
version: "1.0"
|
||||||
title: "rynDNS"
|
title: "rynDNS"
|
||||||
|
|
||||||
servers:
|
servers:
|
||||||
- url: "https://api.pdev.dev/rynDNS/v1"
|
- url: "https://demo.api.pdev.dev/rynDNS"
|
||||||
description: ""
|
description: ""
|
||||||
|
|
||||||
security:
|
security:
|
||||||
@@ -49,6 +72,8 @@ paths:
|
|||||||
description: "Invalid input"
|
description: "Invalid input"
|
||||||
"406":
|
"406":
|
||||||
description: "Not Acceptable - Can not remove last admin account permissions"
|
description: "Not Acceptable - Can not remove last admin account permissions"
|
||||||
|
"429":
|
||||||
|
description: "Too many clients - Maximum client count reached"
|
||||||
put:
|
put:
|
||||||
tags:
|
tags:
|
||||||
- "admin"
|
- "admin"
|
||||||
@@ -356,5 +381,5 @@ components:
|
|||||||
example: "115.16.0.99"
|
example: "115.16.0.99"
|
||||||
pattern: "^(((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(.(?!$)|$)){4})?$"
|
pattern: "^(((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(.(?!$)|$)){4})?$"
|
||||||
externalDocs:
|
externalDocs:
|
||||||
description: "Source"
|
description: "<rynDNS source code>"
|
||||||
url: "https://git.pdev.dev"
|
url: "https://git.pdev.dev/pdev/ryndns"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class ClientsController < ApplicationController
|
|||||||
before_action :authorize_perm_w, only: %i[update_ipv4 destroy_ipv4]
|
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 :authorize_perm_x, only: %i[create update index show destroy]
|
||||||
before_action :client_authorized, except: [:show_public_ipv4]
|
before_action :client_authorized, except: [:show_public_ipv4]
|
||||||
|
before_action :demo, only: %i[create update destroy] if ENV['RAILS_API_DEMO']
|
||||||
|
|
||||||
# URL Methods
|
# URL Methods
|
||||||
# POST /admin/client
|
# POST /admin/client
|
||||||
@@ -22,6 +23,7 @@ class ClientsController < ApplicationController
|
|||||||
# create new client or update existing
|
# create new client or update existing
|
||||||
if client.nil?
|
if client.nil?
|
||||||
client ||= Client.new_client(client_params)
|
client ||= Client.new_client(client_params)
|
||||||
|
return head(429) if client.nil? # reached max client count
|
||||||
else
|
else
|
||||||
# return 406 if request is trying to remove perm_x from last admin account to prevent lockout
|
# return 406 if request is trying to remove perm_x from last admin account to prevent lockout
|
||||||
# TODO: move this into the model (update)
|
# TODO: move this into the model (update)
|
||||||
@@ -217,4 +219,11 @@ class ClientsController < ApplicationController
|
|||||||
def client_authorized
|
def client_authorized
|
||||||
return head(403) unless @authorized
|
return head(403) unless @authorized
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
class Client < ApplicationRecord
|
class Client < ApplicationRecord
|
||||||
|
|
||||||
def self.new_client(params)
|
def self.new_client(params)
|
||||||
|
return nil if count >= RynDNS::Application::MAX_CLIENTS
|
||||||
|
|
||||||
perm_string = params[:permission] || 'w' # create write client by default
|
perm_string = params[:permission] || 'w' # create write client by default
|
||||||
perm_rwx = Client.parse_perm_string(perm_string)
|
perm_rwx = Client.parse_perm_string(perm_string)
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ class Client < ApplicationRecord
|
|||||||
def gen_api_key
|
def gen_api_key
|
||||||
api_key = SecureRandom.hex(32)
|
api_key = SecureRandom.hex(32)
|
||||||
self.api_key = api_key
|
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
|
end
|
||||||
|
|
||||||
def api_key
|
def api_key
|
||||||
|
|||||||
@@ -58,5 +58,6 @@ module RynDNS
|
|||||||
puts "WARNING: Please modify api_key -> #{API_KEY_PREFIX}.########.############"
|
puts "WARNING: Please modify api_key -> #{API_KEY_PREFIX}.########.############"
|
||||||
end
|
end
|
||||||
API_KEY_HEADER = ENV['RAILS_API_KEY_HEADER'] || 'X-API-Key'
|
API_KEY_HEADER = ENV['RAILS_API_KEY_HEADER'] || 'X-API-Key'
|
||||||
|
MAX_CLIENTS = ENV['RAILS_MAX_CLIENTS'] || 250
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
# set to run app in subdirectory
|
# set to run app in subdirectory
|
||||||
RAILS_RELATIVE_URL_ROOT: /rynDNS
|
RAILS_RELATIVE_URL_ROOT: /rynDNS
|
||||||
|
# set maximum number of clients in db
|
||||||
|
#RAILS_MAX_CLIENTS: 250
|
||||||
# set custom api key prefix
|
# set custom api key prefix
|
||||||
#API_KEY_PREFIX: zW3If4s5
|
#API_KEY_PREFIX: zW3If4s5
|
||||||
# set custom header name for api key
|
# set custom header name for api key
|
||||||
@@ -19,7 +21,7 @@ services:
|
|||||||
# set app to run as demo
|
# set app to run as demo
|
||||||
#RAILS_API_DEMO: 1
|
#RAILS_API_DEMO: 1
|
||||||
# set cycle to reset demo data
|
# set cycle to reset demo data
|
||||||
#RAILS_DEMO_RESET: 300
|
#RAILS_DEMO_RESET: 60m
|
||||||
restart: always
|
restart: always
|
||||||
image: ryndns
|
image: ryndns
|
||||||
container_name: ryndns
|
container_name: ryndns
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ prefix_file="${API_PREFIX_FILE:-/app/data/api_prefix}"
|
|||||||
db_file="${RAILS_DB_PATH:-/app/data/rynDNS.sqlite3}"
|
db_file="${RAILS_DB_PATH:-/app/data/rynDNS.sqlite3}"
|
||||||
default_admin_file="${API_DEFAULT_KEY_FILE:-/app/data/api_default_admin}"
|
default_admin_file="${API_DEFAULT_KEY_FILE:-/app/data/api_default_admin}"
|
||||||
rails_bin="${RAILS_BINARY:-/app/bin/rails}"
|
rails_bin="${RAILS_BINARY:-/app/bin/rails}"
|
||||||
demo_cycle="${RAILS_DEMO_RESET:-300s}"
|
demo_cycle="${RAILS_DEMO_RESET:-60m}"
|
||||||
demo_prefix="zW3If4s5"
|
demo_prefix="zW3If4s5"
|
||||||
seed_default_key_text="Created default admin with api_key" # for grep'ing the default admin key
|
seed_default_key_text="Created default admin with api_key" # for grep'ing the default admin key
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,20 @@ RSpec.describe 'Clients', type: :request do
|
|||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
describe 'PUT /admin/client' do
|
describe 'PUT /admin/client' do
|
||||||
|
|||||||
Reference in New Issue
Block a user