From b4799ae80e64bf4cfdbe1724bf487e03019ae251 Mon Sep 17 00:00:00 2001 From: Ben Teitelbaum Date: Fri, 8 Feb 2019 13:34:40 -0800 Subject: [PATCH] add error codes for other errors #3 --- error_handlers.rb | 17 ++++++++++++++- helpers/invoice_helpers.rb | 21 ++++++++++++++---- helpers/order_helpers.rb | 44 ++++++++++++++++++++++++++++++++++++-- main.rb | 28 ++++++++++++------------ tests/tests.rb | 16 +++++++++----- 5 files changed, 100 insertions(+), 26 deletions(-) diff --git a/error_handlers.rb b/error_handlers.rb index cf525b4..e5a4e71 100644 --- a/error_handlers.rb +++ b/error_handlers.rb @@ -39,7 +39,22 @@ class ERROR BID_INCREASE_MISSING: 105, BID_INCREASE_TOO_SMALL: 106, LID_MISSING: 107, - CHARGED_AUTH_TOKEN_MISSING: 108 + CHARGED_AUTH_TOKEN_MISSING: 108, + INVALID_AUTH_TOKEN: 109, + LIGHTNING_CHARGE_INVOICE_ERROR: 110, + LIGHTNING_CHARGE_WEBHOOK_REGISTRATION_ERROR: 111, + INVOICE_ID_NOT_FOUND_ERROR: 112, + INVALID_DATE: 113, + SEQUENCE_NUMBER_NOT_FOUND: 114, + MESSAGE_FILE_MISSING: 115, + MESSAGE_FILENAME_MISSING: 116, + MESSAGE_FILE_TOO_SMALL: 117, + MESSAGE_FILE_TOO_LARGE: 118, + ORDER_BUMP_ERROR: 119, + ORDER_CANCELLATION_ERROR: 120, + INVOICE_NOT_FOUND: 121, + ORPHANED_INVOICE: 122, + ORDER_ALREADY_PAID: 123 } def self.code(p, e) diff --git a/helpers/invoice_helpers.rb b/helpers/invoice_helpers.rb index 6058daf..6f1522a 100644 --- a/helpers/invoice_helpers.rb +++ b/helpers/invoice_helpers.rb @@ -4,12 +4,13 @@ module Sinatra module InvoiceHelpers def fetch_invoice_by_lid - Invoice.where(lid: params[:lid]).first || halt(404, {:message => "Not found", :errors => ["Invalid invoice id"]}.to_json) + Invoice.where(lid: params[:lid]).first || + error_object("Not found", "Invoice id #{params[:lib]} not found", ERROR::CODES[:INVOICE_ID_NOT_FOUND_ERROR]) end def authorize_invoice!(invoice) if invoice.charged_auth_token != params[:charged_auth_token] - halt 401, {:message => "Unauthorized", :errors => ["Invalid authentication token"]}.to_json + halt 401, error_object("Unauthorized", "Invalid authentication token", ERROR::CODES[:INVALID_AUTH_TOKEN]) else invoice end @@ -29,7 +30,7 @@ module Sinatra metadata: {uuid: order.uuid, sha256_message_digest: order.message_digest} } unless charged_response.status == 201 - halt 400, {:message => "Lightning Charge invoice creation error", :errors => ["received #{response.status} from charged"]}.to_json + halt 400, error_object("Lightning Charge invoice creation error", "received #{response.status} from charged", ERROR::CODES[:LIGHTNING_CHARGE_INVOICE_ERROR]) end lightning_invoice = JSON.parse(charged_response.body) @@ -40,10 +41,22 @@ module Sinatra url: invoice.callback_url } unless webhook_registration_response.status == 201 - halt 400, {:message => "Lightning Charge webhook registration error", :errors => ["received #{response.status} from charged"]}.to_json + halt 400, error_object("Lightning Charge webhook registration error", "received #{response.status} from charged", ERROR::CODES[:LIGHTNING_CHARGE_WEBHOOK_REGISTRATION_ERROR]) end invoice end + + def invoice_not_found_error + halt 404, error_object("Payment problem", "Invoice not found", ERROR::CODES[:INVOICE_NOT_FOUND]) + end + + def orphaned_invoice_error + halt 404, error_object("Payment problem", "Orphaned invoice", ERROR::CODES[:ORPHANED_INVOICE]) + end + + def order_already_paid_error + halt 400, error_object("Payment problem", "Order already paid", ERROR::CODES[:ORDER_ALREADY_PAID]) + end end helpers InvoiceHelpers diff --git a/helpers/order_helpers.rb b/helpers/order_helpers.rb index d980caf..d8c0293 100644 --- a/helpers/order_helpers.rb +++ b/helpers/order_helpers.rb @@ -2,12 +2,12 @@ module Sinatra module OrderHelpers def fetch_order_by_uuid - Order.where(uuid: params[:uuid]).first || halt(404, {:message => "Not found", :errors => ["Invalid order id"]}.to_json) + Order.where(uuid: params[:uuid]).first || uuid_not_found_error end def authorize_order!(order) if order.user_auth_token != params[:auth_token] - halt 401, {:message => "Unauthorized", :errors => ["Invalid authentication token"]}.to_json + halt 401, error_object("Unauthorized", "Invalid authentication token", ERROR::CODES[:INVALID_AUTH_TOKEN]) else order end @@ -16,6 +16,46 @@ module Sinatra def get_and_authenticate_order authorize_order!(fetch_order_by_uuid) end + + def invalid_date_error + halt 400, error_object("Invalid date", "Couldn't parse date given by before param", ERROR::CODES[:INVALID_DATE]) + end + + def sequence_number_not_found_error + halt 404, error_object("Sequence number not found", "Sent order with that tx sequence number not found", ERROR::CODES[:SEQUENCE_NUMBER_NOT_FOUND]) + end + + def uuid_not_found_error + halt 404, error_object("UUID not found", "UUID #{params[:uuid]} not found", ERROR::CODES[:UUID_MISSING]) + end + + def message_file_missing_error + halt 400, error_object("Message upload problem", "No tempfile received", ERROR::CODES[:MESSAGE_FILE_MISSING]) + end + + def message_filename_missing_error + halt 400, error_object("Message upload problem", "Filename missing", ERROR::CODES[:MESSAGE_FILENAME_MISSING]) + end + + def message_file_too_large_error + halt 413, error_object("Message upload problem", "Message size exceeds max size #{MAX_MESSAGE_SIZE}", ERROR::CODES[:MESSAGE_FILE_TOO_LARGE]) + end + + def message_file_too_small_error + halt 400, error_object("Message upload problem", "Message too small. Minimum message size is #{MIN_MESSAGE_SIZE} byte", ERROR::CODES[:MESSAGE_FILE_TOO_SMALL]) + end + + def bid_too_small_error(min_bid) + halt 413, error_object("Bid too low", "Per byte bid cannot be below #{MIN_PER_BYTE_BID} millisatoshis per byte. The minimum bid for this message is #{min_bid} millisatoshis.", ERROR::CODES[:BID_TOO_SMALL]) + end + + def order_bump_error + halt 400, error_object("Cannot bump order", "Order already #{order.status}", ERROR::CODES[:ORDER_BUMP_ERROR]) + end + + def order_cancellation_error + halt 400, error_object("Cannot cancel order", "Order already #{order.status}", ERROR::CODES[:ORDER_CANCELLATION_ERROR]) + end end helpers OrderHelpers diff --git a/main.rb b/main.rb index 1d72579..12b2ccb 100644 --- a/main.rb +++ b/main.rb @@ -24,7 +24,7 @@ end configure :test, :development do get '/order/:uuid/sent_message' do - (order = Order.find_by(uuid: params[:uuid], status: [:sent, :transmitting])) || halt(404, {:message => "Not found", :errors => ["Sent order with that id not found"]}.to_json) + (order = Order.find_by(uuid: params[:uuid], status: [:sent, :transmitting])) || uuid_not_found_error send_file order.message_path, :disposition => 'attachment' end end @@ -63,7 +63,7 @@ get '/orders/sent' do begin before = DateTime.iso8601(params[:before]) rescue - halt 400, {:message => "Invalid date", :errors => ["Couldn't parse date given by before param"]}.to_json + invalid_date_error end Order.where(status: :sent).where("created_at < ?", before) .select(Order::PUBLIC_FIELDS) @@ -81,7 +81,7 @@ get '/orders/pending' do begin before = DateTime.iso8601(params[:before]) rescue - halt 400, {:message => "Invalid date", :errors => ["Couldn't parse date given by before param"]}.to_json + invalid_date_error end Order.where(status: :pending).where("created_at < ?", before) .select(Order::PUBLIC_FIELDS) @@ -90,7 +90,7 @@ get '/orders/pending' do end get '/message/:tx_seq_num' do - (order = Order.find_by(tx_seq_num: params[:tx_seq_num], status: [:sent, :transmitting])) || halt(404, {:message => "Not found", :errors => ["Sent order with that tx sequence number not found"]}.to_json) + (order = Order.find_by(tx_seq_num: params[:tx_seq_num], status: [:sent, :transmitting])) || sequence_number_not_found_error send_file order.message_path, :disposition => 'attachment' end @@ -105,10 +105,10 @@ post '/order' do # process the upload unless tmpfile = params[:file][:tempfile] - halt 400, {:message => "Message upload problem", :errors => ["No tempfile received"]}.to_json + message_file_missing_error end unless name = params[:file][:filename] - halt 400, {:message => "Message upload problem", :errors => ["Filename missing"]}.to_json + message_filename_missing_error end order = Order.new(uuid: SecureRandom.uuid) @@ -118,7 +118,7 @@ post '/order' do while block = tmpfile.read(65536) message_size += block.size if message_size > MAX_MESSAGE_SIZE - halt 413, {:message => "Message upload problem", :errors => ["Message size exceeds max size #{MAX_MESSAGE_SIZE}"]}.to_json + message_file_too_large_error end sha256 << block message_file.write(block) @@ -126,7 +126,7 @@ post '/order' do message_file.close() if message_size < MIN_MESSAGE_SIZE FileUtils.rm(message_file) - halt 400, {:message => "Message upload problem", :errors => ["Message too small. Minimum message size is #{MIN_MESSAGE_SIZE} byte"]}.to_json + message_file_too_small_error end order.message_size = message_size @@ -135,7 +135,7 @@ post '/order' do message_size_with_overhead = message_size + FRAMING_OVERHEAD_PER_FRAGMENT * (message_size / FRAGMENT_SIZE).ceil if bid.to_f / message_size_with_overhead.to_f < MIN_PER_BYTE_BID - halt 413, {:message => "Bid too low", :errors => ["Per byte bid cannot be below #{MIN_PER_BYTE_BID} millisatoshis per byte. The minimum bid for this message is #{message_size_with_overhead * MIN_PER_BYTE_BID} millisatoshis." ]}.to_json + bid_too_small_error(message_size_with_overhead * MIN_PER_BYTE_BID) end invoice = new_invoice(order, bid) @@ -154,7 +154,7 @@ post '/order/:uuid/bump' do order = get_and_authenticate_order unless order.bump - halt 400, {:message => "Cannot bump order", :errors => ["Order already #{order.status}"]}.to_json + order_bump_error end invoice = new_invoice(order, bid_increase) @@ -178,7 +178,7 @@ delete '/order/:uuid' do order = get_and_authenticate_order unless order.cancel! - halt 400, {:message => "Cannot cancel order", :errors => ["Order already #{order.status}"]}.to_json + order_cancellation_error end {:message => "order cancelled"}.to_json @@ -191,15 +191,15 @@ post '/callback/:lid/:charged_auth_token' do invoice = get_and_authenticate_invoice if invoice.nil? - halt 404, {:message => "Payment problem", :errors => ["Invoice not found"]}.to_json + invoice_not_found_error end unless invoice.order - halt 404, {:message => "Payment problem", :errors => ["Orphaned invoice"]}.to_json + orphaned_invoice_error end if invoice.paid? - halt 400, {:message => "Payment problem", :errors => ["Order already paid"]}.to_json + order_already_paid_error end invoice.pay! diff --git a/tests/tests.rb b/tests/tests.rb index 14d700a..d173821 100644 --- a/tests/tests.rb +++ b/tests/tests.rb @@ -114,9 +114,7 @@ class MainAppTest < Minitest::Test def test_bid_too_low post '/order', params={"bid" => 1, "file" => Rack::Test::UploadedFile.new(TEST_FILE, "image/png")} refute last_response.ok? - r = JSON.parse(last_response.body) - assert_equal r['message'], 'Bid too low' - refute_nil r['errors'] + assert_equal ERROR::CODES[:BID_TOO_SMALL], last_response_error_code end def test_no_file_uploaded @@ -132,8 +130,7 @@ class MainAppTest < Minitest::Test def test_uploaded_file_too_small post '/order', params={"bid" => DEFAULT_BID, "file" => Rack::Test::UploadedFile.new(TINY_TEST_FILE, "text/plain")} refute last_response.ok? - r = JSON.parse(last_response.body) - assert_match "too small", r["errors"][0] + assert_equal ERROR::CODES[:MESSAGE_FILE_TOO_SMALL], last_response_error_code end def test_bid_increase_missing_error @@ -149,6 +146,13 @@ class MainAppTest < Minitest::Test assert_equal ERROR::CODES[:BID_INCREASE_TOO_SMALL], last_response_error_code end + def test_invalid_auth_token_error + header 'X-Auth-Token', "not an auth token" + post "/order/#{@order.uuid}/bump", params={"bid_increase" => DEFAULT_BID / 2} + refute last_response.ok? + assert_equal ERROR::CODES[:INVALID_AUTH_TOKEN], last_response_error_code + end + def test_bump # place an order @order = place_order @@ -212,6 +216,7 @@ class MainAppTest < Minitest::Test def test_that_bumping_down_fails bump_order(@order, -1) refute last_response.ok? + assert_equal ERROR::CODES[:BID_INCREASE_TOO_SMALL], last_response_error_code end def test_order_deletion @@ -232,6 +237,7 @@ class MainAppTest < Minitest::Test @order = place_order get "/order/#{@order.uuid}/sent_message" refute last_response.ok? + assert_equal ERROR::CODES[:UUID_MISSING], last_response_error_code pay_invoice(@order.invoices.last) @order.reload