Commit b2341ba5 authored by Nina's avatar Nina

Extract schleuder api daemon helper

parent e5ca92d7
......@@ -14,6 +14,7 @@ require 'schleuder-api-daemon/routes/version'
require 'schleuder-api-daemon/routes/list'
require 'schleuder-api-daemon/routes/subscription'
require 'schleuder-api-daemon/routes/key'
require 'schleuder-api-daemon/helpers/schleuder-api-daemon-helper'
%w[tls_cert_file tls_key_file].each do |config_key|
path = Conf.api[config_key]
......@@ -24,6 +25,8 @@ require 'schleuder-api-daemon/routes/key'
end
class SchleuderApiDaemon < Sinatra::Base
helpers SchleuderApiDaemonHelper
configure do
set :server, :thin
set :port, Schleuder::Conf.api['port'] || 4443
......@@ -60,150 +63,6 @@ class SchleuderApiDaemon < Sinatra::Base
'Not found'
end
helpers do
def valid_credentials?
@auth ||= Rack::Auth::Basic::Request.new(request.env)
if @auth.provided? && @auth.basic? && @auth.credentials.present?
username, api_key = @auth.credentials
username == 'schleuder' && Conf.api_valid_api_keys.include?(api_key)
else
false
end
end
def authenticate!
# Be careful to use path_info() — it can be changed by other filters!
return if request.path_info == '/status.json'
if ! valid_credentials?
headers['WWW-Authenticate'] = 'Basic realm="Schleuder API Daemon"'
halt 401, "Not authorized\n"
end
end
def list(id_or_email=nil)
if id_or_email.blank?
if params[:list_id].present?
id_or_email = params[:list_id]
else
client_error "Parameter list_id is required"
end
end
if is_an_integer?(id_or_email)
list = List.where(id: id_or_email).first
else
# list_id is actually an email address
list = List.where(email: id_or_email).first
end
list || halt(404)
end
def subscription(id_or_email)
if is_an_integer?(id_or_email)
sub = Subscription.where(id: id_or_email.to_i).first
else
# Email
if params[:list_id].blank?
client_error "Parameter list_id is required when using email as identifier for subscriptions."
else
sub = list.subscriptions.where(email: id_or_email).first
end
end
sub || halt(404)
end
def requested_list_id
# ActiveResource doesn't want to use query-params with create(), so here
# list_id might be included in the request-body.
params['list_id'] || parsed_body['list_id'] || client_error('Need list_id')
end
def parsed_body
@parsed_body ||= begin
b = JSON.parse(request.body.read)
logger.debug "parsed body: #{b.inspect}"
b
end
end
def server_error(msg)
logger.warn msg
halt(500, json(error: msg))
end
# TODO: unify error messages. This method currently sends an old error format. See <https://github.com/rails/activeresource/blob/d6a5186/lib/active_resource/base.rb#L227>.
def client_error(obj_or_msg, http_code=400)
text = case obj_or_msg
when String, Symbol
obj_or_msg.to_s
when ActiveRecord::Base
obj_or_msg.errors.full_messages
else
obj_or_msg
end
logger.error "Sending error to client: #{text.inspect}"
halt(http_code, json(errors: text))
end
# poor persons type casting
def cast_param_values
params.each do |key, value|
params[key] =
case value
when 'true' then true
when 'false' then false
when '0' then 0
when is_an_integer?(value) then value.to_i
else value
end
end
end
def key_to_hash(key, include_keydata=false)
hash = {
fingerprint: key.fingerprint,
email: key.email,
expiry: key.expires,
generated_at: key.generated_at,
primary_uid: key.primary_uid.uid,
oneline: key.oneline,
trust_issues: key.usability_issue
}
if include_keydata
hash[:description] = key.to_s
hash[:ascii] = key.armored
end
hash
end
def set_x_messages(messages)
if messages.present?
headers 'X-Messages' => Array(messages).join(' // ').gsub(/\n/, ' // ')
end
end
def find_key_material
key_material = parsed_body['key_material'].presence
# By convention key_material is either ASCII or base64-encoded.
if key_material && ! key_material.match('BEGIN PGP')
key_material = Base64.decode64(key_material)
end
key_material
end
def find_attributes_from_body(attribs)
Array(attribs).inject({}) do |memo, attrib|
if parsed_body.has_key?(attrib)
memo[attrib] = parsed_body[attrib]
end
memo
end
end
def is_an_integer?(input)
input.to_s.match(/^[0-9]+$/).present?
end
end
def self.run!
super do |server|
server.ssl = true
......
module SchleuderApiDaemonHelper
def valid_credentials?
@auth ||= Rack::Auth::Basic::Request.new(request.env)
if @auth.provided? && @auth.basic? && @auth.credentials.present?
username, api_key = @auth.credentials
username == 'schleuder' && Conf.api_valid_api_keys.include?(api_key)
else
false
end
end
def authenticate!
# Be careful to use path_info() — it can be changed by other filters!
return if request.path_info == '/status.json'
if ! valid_credentials?
headers['WWW-Authenticate'] = 'Basic realm="Schleuder API Daemon"'
halt 401, "Not authorized\n"
end
end
def list(id_or_email=nil)
if id_or_email.blank?
if params[:list_id].present?
id_or_email = params[:list_id]
else
client_error "Parameter list_id is required"
end
end
if is_an_integer?(id_or_email)
list = List.where(id: id_or_email).first
else
# list_id is actually an email address
list = List.where(email: id_or_email).first
end
list || halt(404)
end
def subscription(id_or_email)
if is_an_integer?(id_or_email)
sub = Subscription.where(id: id_or_email.to_i).first
else
# Email
if params[:list_id].blank?
client_error "Parameter list_id is required when using email as identifier for subscriptions."
else
sub = list.subscriptions.where(email: id_or_email).first
end
end
sub || halt(404)
end
def requested_list_id
# ActiveResource doesn't want to use query-params with create(), so here
# list_id might be included in the request-body.
params['list_id'] || parsed_body['list_id'] || client_error('Need list_id')
end
def parsed_body
@parsed_body ||= begin
b = JSON.parse(request.body.read)
logger.debug "parsed body: #{b.inspect}"
b
end
end
def server_error(msg)
logger.warn msg
halt(500, json(error: msg))
end
# TODO: unify error messages. This method currently sends an old error format. See <https://github.com/rails/activeresource/blob/d6a5186/lib/active_resource/base.rb#L227>.
def client_error(obj_or_msg, http_code=400)
text = case obj_or_msg
when String, Symbol
obj_or_msg.to_s
when ActiveRecord::Base
obj_or_msg.errors.full_messages
else
obj_or_msg
end
logger.error "Sending error to client: #{text.inspect}"
halt(http_code, json(errors: text))
end
# poor persons type casting
def cast_param_values
params.each do |key, value|
params[key] =
case value
when 'true' then true
when 'false' then false
when '0' then 0
when is_an_integer?(value) then value.to_i
else value
end
end
end
def key_to_hash(key, include_keydata=false)
hash = {
fingerprint: key.fingerprint,
email: key.email,
expiry: key.expires,
generated_at: key.generated_at,
primary_uid: key.primary_uid.uid,
oneline: key.oneline,
trust_issues: key.usability_issue
}
if include_keydata
hash[:description] = key.to_s
hash[:ascii] = key.armored
end
hash
end
def set_x_messages(messages)
if messages.present?
headers 'X-Messages' => Array(messages).join(' // ').gsub(/\n/, ' // ')
end
end
def find_key_material
key_material = parsed_body['key_material'].presence
# By convention key_material is either ASCII or base64-encoded.
if key_material && ! key_material.match('BEGIN PGP')
key_material = Base64.decode64(key_material)
end
key_material
end
def find_attributes_from_body(attribs)
Array(attribs).inject({}) do |memo, attrib|
if parsed_body.has_key?(attrib)
memo[attrib] = parsed_body[attrib]
end
memo
end
end
def is_an_integer?(input)
input.to_s.match(/^[0-9]+$/).present?
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment