From c4cb76fe0bb88c76a1ea0f371d87851fbc2cd59b Mon Sep 17 00:00:00 2001 From: Pascal Date: Sun, 7 Mar 2021 16:39:38 -0500 Subject: [PATCH] [add] added public mode --- api.yml | 33 ++++++++++++++++++++ app/controllers/clients_controller.rb | 32 +++++++++++++++++-- config/routes.rb | 1 + spec/requests/clients_request_spec.rb | 45 +++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 2 deletions(-) diff --git a/api.yml b/api.yml index fb34af6..74c0dbf 100644 --- a/api.yml +++ b/api.yml @@ -253,6 +253,39 @@ paths: $ref: "#/components/schemas/client_info" "401": $ref: "#/components/responses/unauthorized_public" + post: + tags: + - "public" + summary: "Set ipv4 client information. This is ONLY available if ENV['RAILS_API_PUBLIC'] is set" + description: "If body is present, it will take precedence over the request IP. Response contains the newly set `ipv4` value." + requestBody: + description: "An existing clients properties wil only be updated if the parameter is present." + required: false + content: + application/json: + schema: + $ref: "#/components/schemas/client_update" + operationId: "set_public_client_ip" + security: [] + responses: + "200": + description: "Client created" + content: + application/json: + schema: + $ref: "#/components/schemas/client_info" + "201": + description: "Client updated" + content: + application/json: + schema: + $ref: "#/components/schemas/client_info" + "403": + description: "Forbidden - API not public" + "406": + description: "Not Acceptable - IPv4 Address is invalid" + "429": + description: "Too many clients - Maximum client count reached" components: diff --git a/app/controllers/clients_controller.rb b/app/controllers/clients_controller.rb index bb1537e..e6c2eb4 100644 --- a/app/controllers/clients_controller.rb +++ b/app/controllers/clients_controller.rb @@ -3,11 +3,12 @@ require 'resolv' class ClientsController < ApplicationController - before_action :parse_api_key_header, except: [:show_public_ipv4] - before_action :authenticate_client, except: [:show_public_ipv4] + before_action :parse_api_key_header, except: %i[show_public_ipv4 create_public_ipv4] + before_action :authenticate_client, except: %i[show_public_ipv4 create_public_ipv4] before_action :authorize_perm_r, only: [:show_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_public, only: [:create_public_ipv4] if ENV['RAILS_API_PUBLIC'] before_action :client_authorized, except: [:show_public_ipv4] before_action :demo, only: %i[create update destroy] if ENV['RAILS_API_DEMO'] @@ -129,6 +130,29 @@ class ClientsController < ApplicationController json_response(client_read_object(client)) end + # POST /public/:id + def create_public_ipv4 + ipv4 = request_ip + + # return 406 if body with invalid ipv4 is present + # TODO: move this into the model (update) + return head(406) unless ipv4 + + client_params = params.permit(:name) + client = Client.find_by name: params[:name] + status_code = client ? 200 : 201 + + # 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 + end + client.public_ip = true + client.ipv4 = ipv4 + client.save + json_response(client_read_object(client), status_code) + end + private # helper methods @@ -215,6 +239,10 @@ class ClientsController < ApplicationController @authorized = @requesting_client.admin? end + def authorize_public + @authorized = true + end + # check if request is authorized def client_authorized return head(403) unless @authorized diff --git a/config/routes.rb b/config/routes.rb index ac8b5c0..46d047a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -21,6 +21,7 @@ Rails.application.routes.draw do # separate public path to allow for easier segregation and controls via reverse proxy scope '/public' do get ':name', to: 'clients#show_public_ipv4', format: false + post ':name', to: 'clients#create_public_ipv4', format: false end end end diff --git a/spec/requests/clients_request_spec.rb b/spec/requests/clients_request_spec.rb index 87e041a..cdf299e 100644 --- a/spec/requests/clients_request_spec.rb +++ b/spec/requests/clients_request_spec.rb @@ -587,4 +587,49 @@ RSpec.describe 'Clients', type: :request do end end end + + describe 'POST /public/:name' do + # FIXME: rather have this automated than adding ENV by hand + if ENV['RAILS_API_PUBLIC'] + + context 'when request to write public client' do + before { post "/public/#{public_client.name}" } + it 'returns status code 200' do + expect(json_response['name']).to eq public_client.name + expect(json_response['ipv4']).to eq '127.0.0.1' + expect(response).to have_http_status(200) + end + end + + context 'when requesting to write public client with body' do + before { post "/public/#{public_client.name}", params: { ipv4: '99.55.66.2' } } + it 'returns status code 200' do + expect(json_response['name']).to eq public_client.name + expect(json_response['ipv4']).to eq '99.55.66.2' + expect(response).to have_http_status(200) + end + end + + context 'when requesting to write non existing client' do + before { post "/public/#{non_existing_client}" } + it 'returns status code 201' do + expect(json_response['name']).to eq non_existing_client + expect(json_response['ipv4']).to eq '127.0.0.1' + expect(response).to have_http_status(201) + end + end + # TODO: 406 and 429, check client count on 200 + else + + context 'when request to write public client' do + before { post "/public/#{public_client.name}" } + it 'returns status code 403' do + expect(response.body).to be_empty + expect(response).to have_http_status(403) + end + end + # TODO: check client count/modification + + end + end end -- 2.49.1