add error codes for other errors #3

This commit is contained in:
Ben Teitelbaum 2019-02-08 13:34:40 -08:00
parent 980683fd65
commit b4799ae80e
5 changed files with 100 additions and 26 deletions

View file

@ -39,7 +39,22 @@ class ERROR
BID_INCREASE_MISSING: 105, BID_INCREASE_MISSING: 105,
BID_INCREASE_TOO_SMALL: 106, BID_INCREASE_TOO_SMALL: 106,
LID_MISSING: 107, 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) def self.code(p, e)

View file

@ -4,12 +4,13 @@ module Sinatra
module InvoiceHelpers module InvoiceHelpers
def fetch_invoice_by_lid 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 end
def authorize_invoice!(invoice) def authorize_invoice!(invoice)
if invoice.charged_auth_token != params[:charged_auth_token] 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 else
invoice invoice
end end
@ -29,7 +30,7 @@ module Sinatra
metadata: {uuid: order.uuid, sha256_message_digest: order.message_digest} metadata: {uuid: order.uuid, sha256_message_digest: order.message_digest}
} }
unless charged_response.status == 201 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 end
lightning_invoice = JSON.parse(charged_response.body) lightning_invoice = JSON.parse(charged_response.body)
@ -40,10 +41,22 @@ module Sinatra
url: invoice.callback_url url: invoice.callback_url
} }
unless webhook_registration_response.status == 201 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 end
invoice invoice
end 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 end
helpers InvoiceHelpers helpers InvoiceHelpers

View file

@ -2,12 +2,12 @@ module Sinatra
module OrderHelpers module OrderHelpers
def fetch_order_by_uuid 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 end
def authorize_order!(order) def authorize_order!(order)
if order.user_auth_token != params[:auth_token] 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 else
order order
end end
@ -16,6 +16,46 @@ module Sinatra
def get_and_authenticate_order def get_and_authenticate_order
authorize_order!(fetch_order_by_uuid) authorize_order!(fetch_order_by_uuid)
end 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 end
helpers OrderHelpers helpers OrderHelpers

28
main.rb
View file

@ -24,7 +24,7 @@ end
configure :test, :development do configure :test, :development do
get '/order/:uuid/sent_message' 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' send_file order.message_path, :disposition => 'attachment'
end end
end end
@ -63,7 +63,7 @@ get '/orders/sent' do
begin begin
before = DateTime.iso8601(params[:before]) before = DateTime.iso8601(params[:before])
rescue rescue
halt 400, {:message => "Invalid date", :errors => ["Couldn't parse date given by before param"]}.to_json invalid_date_error
end end
Order.where(status: :sent).where("created_at < ?", before) Order.where(status: :sent).where("created_at < ?", before)
.select(Order::PUBLIC_FIELDS) .select(Order::PUBLIC_FIELDS)
@ -81,7 +81,7 @@ get '/orders/pending' do
begin begin
before = DateTime.iso8601(params[:before]) before = DateTime.iso8601(params[:before])
rescue rescue
halt 400, {:message => "Invalid date", :errors => ["Couldn't parse date given by before param"]}.to_json invalid_date_error
end end
Order.where(status: :pending).where("created_at < ?", before) Order.where(status: :pending).where("created_at < ?", before)
.select(Order::PUBLIC_FIELDS) .select(Order::PUBLIC_FIELDS)
@ -90,7 +90,7 @@ get '/orders/pending' do
end end
get '/message/:tx_seq_num' do 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' send_file order.message_path, :disposition => 'attachment'
end end
@ -105,10 +105,10 @@ post '/order' do
# process the upload # process the upload
unless tmpfile = params[:file][:tempfile] unless tmpfile = params[:file][:tempfile]
halt 400, {:message => "Message upload problem", :errors => ["No tempfile received"]}.to_json message_file_missing_error
end end
unless name = params[:file][:filename] unless name = params[:file][:filename]
halt 400, {:message => "Message upload problem", :errors => ["Filename missing"]}.to_json message_filename_missing_error
end end
order = Order.new(uuid: SecureRandom.uuid) order = Order.new(uuid: SecureRandom.uuid)
@ -118,7 +118,7 @@ post '/order' do
while block = tmpfile.read(65536) while block = tmpfile.read(65536)
message_size += block.size message_size += block.size
if message_size > MAX_MESSAGE_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 end
sha256 << block sha256 << block
message_file.write(block) message_file.write(block)
@ -126,7 +126,7 @@ post '/order' do
message_file.close() message_file.close()
if message_size < MIN_MESSAGE_SIZE if message_size < MIN_MESSAGE_SIZE
FileUtils.rm(message_file) 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 end
order.message_size = message_size 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 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 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 end
invoice = new_invoice(order, bid) invoice = new_invoice(order, bid)
@ -154,7 +154,7 @@ post '/order/:uuid/bump' do
order = get_and_authenticate_order order = get_and_authenticate_order
unless order.bump unless order.bump
halt 400, {:message => "Cannot bump order", :errors => ["Order already #{order.status}"]}.to_json order_bump_error
end end
invoice = new_invoice(order, bid_increase) invoice = new_invoice(order, bid_increase)
@ -178,7 +178,7 @@ delete '/order/:uuid' do
order = get_and_authenticate_order order = get_and_authenticate_order
unless order.cancel! unless order.cancel!
halt 400, {:message => "Cannot cancel order", :errors => ["Order already #{order.status}"]}.to_json order_cancellation_error
end end
{:message => "order cancelled"}.to_json {:message => "order cancelled"}.to_json
@ -191,15 +191,15 @@ post '/callback/:lid/:charged_auth_token' do
invoice = get_and_authenticate_invoice invoice = get_and_authenticate_invoice
if invoice.nil? if invoice.nil?
halt 404, {:message => "Payment problem", :errors => ["Invoice not found"]}.to_json invoice_not_found_error
end end
unless invoice.order unless invoice.order
halt 404, {:message => "Payment problem", :errors => ["Orphaned invoice"]}.to_json orphaned_invoice_error
end end
if invoice.paid? if invoice.paid?
halt 400, {:message => "Payment problem", :errors => ["Order already paid"]}.to_json order_already_paid_error
end end
invoice.pay! invoice.pay!

View file

@ -114,9 +114,7 @@ class MainAppTest < Minitest::Test
def test_bid_too_low def test_bid_too_low
post '/order', params={"bid" => 1, "file" => Rack::Test::UploadedFile.new(TEST_FILE, "image/png")} post '/order', params={"bid" => 1, "file" => Rack::Test::UploadedFile.new(TEST_FILE, "image/png")}
refute last_response.ok? refute last_response.ok?
r = JSON.parse(last_response.body) assert_equal ERROR::CODES[:BID_TOO_SMALL], last_response_error_code
assert_equal r['message'], 'Bid too low'
refute_nil r['errors']
end end
def test_no_file_uploaded def test_no_file_uploaded
@ -132,8 +130,7 @@ class MainAppTest < Minitest::Test
def test_uploaded_file_too_small def test_uploaded_file_too_small
post '/order', params={"bid" => DEFAULT_BID, "file" => Rack::Test::UploadedFile.new(TINY_TEST_FILE, "text/plain")} post '/order', params={"bid" => DEFAULT_BID, "file" => Rack::Test::UploadedFile.new(TINY_TEST_FILE, "text/plain")}
refute last_response.ok? refute last_response.ok?
r = JSON.parse(last_response.body) assert_equal ERROR::CODES[:MESSAGE_FILE_TOO_SMALL], last_response_error_code
assert_match "too small", r["errors"][0]
end end
def test_bid_increase_missing_error 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 assert_equal ERROR::CODES[:BID_INCREASE_TOO_SMALL], last_response_error_code
end 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 def test_bump
# place an order # place an order
@order = place_order @order = place_order
@ -212,6 +216,7 @@ class MainAppTest < Minitest::Test
def test_that_bumping_down_fails def test_that_bumping_down_fails
bump_order(@order, -1) bump_order(@order, -1)
refute last_response.ok? refute last_response.ok?
assert_equal ERROR::CODES[:BID_INCREASE_TOO_SMALL], last_response_error_code
end end
def test_order_deletion def test_order_deletion
@ -232,6 +237,7 @@ class MainAppTest < Minitest::Test
@order = place_order @order = place_order
get "/order/#{@order.uuid}/sent_message" get "/order/#{@order.uuid}/sent_message"
refute last_response.ok? refute last_response.ok?
assert_equal ERROR::CODES[:UUID_MISSING], last_response_error_code
pay_invoice(@order.invoices.last) pay_invoice(@order.invoices.last)
@order.reload @order.reload