diff --git a/src/handlers/auth_handler.cr b/src/handlers/auth_handler.cr index ad25d43..472e60d 100644 --- a/src/handlers/auth_handler.cr +++ b/src/handlers/auth_handler.cr @@ -59,6 +59,10 @@ class AuthHandler < Kemal::Handler end def call(env) + # OPTIONS requests do not require authentication + if env.request.method === "OPTIONS" + return call_next(env) + end # Skip all authentication if requesting /login, /logout, /api/login, # or a static file if request_path_startswith(env, ["/login", "/logout", "/api/login"]) || diff --git a/src/handlers/cors_handler.cr b/src/handlers/cors_handler.cr new file mode 100644 index 0000000..d199b12 --- /dev/null +++ b/src/handlers/cors_handler.cr @@ -0,0 +1,8 @@ +class CORSHandler < Kemal::Handler + def call(env) + if request_path_startswith env, ["/api"] + env.response.headers["Access-Control-Allow-Origin"] = "*" + end + call_next env + end +end diff --git a/src/routes/api.cr b/src/routes/api.cr index 413c318..a0f7cfb 100644 --- a/src/routes/api.cr +++ b/src/routes/api.cr @@ -63,6 +63,11 @@ struct APIRouter "username" => String, "password" => String, } + Koa.response 200, schema: { + "success" => Bool, + "error" => String?, + "token" => String?, + } Koa.tag "users" post "/api/login" do |env| begin @@ -71,11 +76,17 @@ struct APIRouter token = Storage.default.verify_user(username, password).not_nil! env.session.string "token", token - "Authenticated" + send_json env, { + "success" => true, + "token" => token, + }.to_json rescue e Logger.error e env.response.status_code = 403 - e.message + send_json env, { + "success" => false, + "error" => e.message, + }.to_json end end @@ -114,7 +125,7 @@ struct APIRouter rescue e Logger.error e env.response.status_code = 500 - e.message + send_text env, e.message end end @@ -151,7 +162,7 @@ struct APIRouter rescue e Logger.error e env.response.status_code = 500 - e.message + send_text env, e.message end end @@ -191,7 +202,7 @@ struct APIRouter rescue e Logger.error e env.response.status_code = 404 - e.message + send_text env, e.message end end @@ -250,6 +261,7 @@ struct APIRouter spawn do Library.default.generate_thumbnails end + send_text env, "" end Koa.describe "Deletes a user with `username`" @@ -675,7 +687,7 @@ struct APIRouter e_tag = "W/#{file_hash}" if e_tag == prev_e_tag env.response.status_code = 304 - "" + send_text env, "" else sizes = entry.page_dimensions env.response.headers["ETag"] = e_tag @@ -709,6 +721,7 @@ struct APIRouter rescue e Logger.error e env.response.status_code = 404 + send_text env, e.message end end diff --git a/src/server.cr b/src/server.cr index e8dc54b..eb79374 100644 --- a/src/server.cr +++ b/src/server.cr @@ -23,7 +23,11 @@ class Server AdminRouter.new ReaderRouter.new APIRouter.new - OPDSRouter.new + + options "/api/*" do |env| + cors + halt env + end Kemal.config.logging = false add_handler LogHandler.new diff --git a/src/util/web.cr b/src/util/web.cr index 5704ea8..e74d4f9 100644 --- a/src/util/web.cr +++ b/src/util/web.cr @@ -39,6 +39,7 @@ macro send_error_page(msg) end macro send_img(env, img) + cors send_file {{env}}, {{img}}.data, {{img}}.mime end @@ -57,12 +58,26 @@ macro get_username(env) end end +macro cors + env.response.headers["Allow"] = "HEAD,GET,PUT,POST,DELETE,OPTIONS" + env.response.headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept, Authorization" + env.response.headers["Access-Control-Allow-Origin"] = "*" +end + def send_json(env, json) + cors env.response.content_type = "application/json" env.response.print json end +def send_text(env, text) + cors + env.response.content_type = "text/plain" + env.response.print text +end + def send_attachment(env, path) + cors send_file env, path, filename: File.basename(path), disposition: "attachment" end