diff --git a/config/config.exs b/config/config.exs index e82be39..6aa2d8c 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,33 +1,38 @@ # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. use Mix.Config # This configuration is loaded before any dependency and is restricted # to this project. If another project depends on this project, this # file won't be loaded nor affect the parent project. For this reason, # if you want to provide default values for your application for # 3rd-party users, it should be done in your "mix.exs" file. # You can configure for your application as: # # config :kolab_wopi, key: :value # # And access this configuration in your application as: # # Application.get_env(:kolab_wopi, :key) # # Or configure a 3rd-party app: # # config :logger, level: :info # # It is also possible to import configuration files, relative to this # directory. For example, you can emulate configuration per environment # by uncommenting the line below and defining dev.exs, test.exs and such. # Configuration from the imported file will override the ones defined # here (which is why it is important to import them last). # # import_config "#{Mix.env}.exs" config :kolab_wopi, + host_info: [ + endpoint_desc: "Kolab Systems, Zurich", + machine_name: to_string(Node.self()), + version: "kolab_wopi_v" <> to_string(Keyword.get(Mix.Project.get!().project(), :version)) #:application.get_key(:kolab_wopi, :description)) + ], chwala_base_url: "http://localhost/chwala/api/" diff --git a/lib/kolab_wopi/api.ex b/lib/kolab_wopi/api.ex index 60d6822..4256461 100644 --- a/lib/kolab_wopi/api.ex +++ b/lib/kolab_wopi/api.ex @@ -1,92 +1,113 @@ defmodule KolabWopi.API do @moduledoc """ An implementation of the Web Application Open Platform Interface (WOPI) API. See https://wopi.readthedocs.io/en/latest/ """ use Plug.Router use Plug.Debugger require Logger plug Plug.Logger + plug :wopi_headers plug :access_token_handler plug :match plug :dispatch def init(options) do options end def start_link do {:ok, _} = Plug.Adapters.Cowboy.http __MODULE__, [] end forward "/wopi/files", to: __MODULE__.Files forward "/wopi/containers", to: __MODULE__.Containers forward "/wopi/ecosystem", to: __MODULE__.Ecosystem forward "/wopibootstrapper", to: __MODULE__.Bootstrap match _ do send_status_resp(conn, 404) end + @doc """ + Plug that adds the standard WOPI response headers + + @see https://wopirest.readthedocs.io/en/latest/common_headers.html + """ + def wopi_headers(conn, _opts) do + host_info = Application.get_env(:kolab_wopi, :host_info) + conn + |> put_resp_header("X-WOPI-HostEndpoint", Keyword.get(host_info, :endpoint_desc)) + |> put_resp_header("X-WOPI-MachineName", Keyword.get(host_info, :machine_name)) + |> put_resp_header("X-WOPI-ServerVersion", Keyword.get(host_info, :version)) + end + @doc """ Plug that fetches query parameters and validates the access_token. The access_token parameter is required in every WOPI request. If it's missing "401 Unauthorized" response will be send and request processing aborted. """ def access_token_handler(conn, _opts) do conn = Plug.Conn.fetch_query_params(conn) token = conn.query_params["access_token"] check_token(conn, token) end # valid token handler defp check_token(conn, token) when is_binary(token) and byte_size(token) > 0 do assign(conn, :access_token, token) end # invalid token handler defp check_token(conn, _) do conn |> send_status_resp(401) |> halt() end @doc """ Sends the response with setting status code. It supports Chwala status codes. """ - def send_status_resp(conn, code, reason \\ nil) + def send_status_resp(conn, code, reason \\ "Unknown error") def send_status_resp(conn, 403, reason) do # Chwala uses only 200, 403, 500, 501, 503 send_status_resp(conn, 401, reason) end + def send_status_resp(conn, code, reason) when code >= 500 and code < 600 do + # TODO: log status reason? + conn + |> put_resp_header("X-WOPI-ServerError", reason) + |> send_resp(code, "") + end + def send_status_resp(conn, code, _reason) do # TODO: log status reason? send_resp(conn, code, "") end @doc """ Return X-WOPI-Override header value. With some buggy collabora versions support. """ def get_wopi_action(conn) do action = case get_req_header(conn, "x-wopi-override") do a when length(a) > 0 -> a _ -> get_req_header(conn, "x-wopioverride") end to_string(action) end end