2018-03-20 05:17:02 +00:00
|
|
|
defmodule PlugMicropub do
|
|
|
|
@moduledoc """
|
|
|
|
A Plug for building a Micropub server.
|
|
|
|
|
|
|
|
To use:
|
|
|
|
|
|
|
|
"""
|
2024-11-29 09:39:35 +00:00
|
|
|
require Logger
|
2018-03-20 05:17:02 +00:00
|
|
|
use Plug.Router
|
2024-11-29 09:39:35 +00:00
|
|
|
alias PlugMicropub.{Parser, Handler, Response}
|
2018-03-20 05:17:02 +00:00
|
|
|
|
2018-04-12 05:50:37 +00:00
|
|
|
plug :match
|
|
|
|
plug :dispatch
|
2018-03-20 05:17:02 +00:00
|
|
|
|
2024-11-29 09:39:35 +00:00
|
|
|
@default_scopes [
|
|
|
|
"create",
|
|
|
|
"media"
|
|
|
|
]
|
|
|
|
|
2018-03-20 05:17:02 +00:00
|
|
|
# Plug Callbacks
|
|
|
|
|
|
|
|
@doc false
|
|
|
|
def init(opts) do
|
2024-11-29 09:39:35 +00:00
|
|
|
hostname =
|
|
|
|
Keyword.get(opts, :hostname) ||
|
|
|
|
raise ArgumentError, "Micropub Plug requires :hostname option"
|
|
|
|
|
2018-03-20 05:17:02 +00:00
|
|
|
handler =
|
|
|
|
Keyword.get(opts, :handler) || raise ArgumentError, "Micropub Plug requires :handler option"
|
|
|
|
|
2024-11-29 09:39:35 +00:00
|
|
|
token_endpoint =
|
|
|
|
Keyword.get(opts, :token_endpoint) ||
|
|
|
|
raise ArgumentError, "Micropub Plug requires :token_endpoint option"
|
|
|
|
|
2018-03-20 05:17:02 +00:00
|
|
|
json_encoder =
|
|
|
|
Keyword.get(opts, :json_encoder) ||
|
|
|
|
raise ArgumentError, "Micropub Plug requires :json_encoder option"
|
|
|
|
|
2024-11-29 09:39:35 +00:00
|
|
|
user_agent =
|
|
|
|
Keyword.get(opts, :user_agent) ||
|
|
|
|
raise ArgumentError, "Micropub Plug requires :user_agent option"
|
|
|
|
|
|
|
|
scopes =
|
|
|
|
Keyword.get(opts, :scopes) || @default_scopes
|
|
|
|
|
|
|
|
token_handler =
|
|
|
|
Keyword.get(opts, :token_handler) || PlugMicropub.Token
|
|
|
|
|
|
|
|
[
|
|
|
|
hostname: hostname,
|
|
|
|
handler: handler,
|
|
|
|
token_handler: token_handler,
|
|
|
|
json_encoder: json_encoder,
|
|
|
|
scopes: scopes,
|
|
|
|
token_endpoint: token_endpoint,
|
|
|
|
user_agent: user_agent
|
|
|
|
]
|
2018-03-20 05:17:02 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
@doc false
|
|
|
|
def call(conn, opts) do
|
|
|
|
conn = put_private(conn, :plug_micropub, opts)
|
|
|
|
super(conn, opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Routes
|
|
|
|
|
|
|
|
post "/" do
|
2024-11-29 09:39:35 +00:00
|
|
|
token_endpoint = get_config(conn, :token_endpoint)
|
|
|
|
supported_scopes = get_config(conn, :scopes)
|
|
|
|
hostname = get_config(conn, :hostname)
|
|
|
|
user_agent = get_config(conn, :user_agent)
|
|
|
|
token_handler = get_config(conn, :token_handler)
|
|
|
|
|
|
|
|
with {:ok, access_token, conn} <- Parser.get_access_token(conn),
|
|
|
|
{:ok, action, conn} <- Parser.get_action(conn),
|
|
|
|
:ok <-
|
|
|
|
token_handler.verify(
|
|
|
|
access_token,
|
|
|
|
token_endpoint,
|
|
|
|
Atom.to_string(action),
|
|
|
|
supported_scopes,
|
|
|
|
hostname,
|
|
|
|
user_agent
|
|
|
|
) do
|
|
|
|
Handler.handle_action(action, access_token, conn)
|
2018-03-20 05:17:02 +00:00
|
|
|
else
|
2024-11-29 09:39:35 +00:00
|
|
|
error -> Response.send_error(conn, error)
|
2018-03-20 05:17:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
get "/" do
|
2024-11-29 09:39:35 +00:00
|
|
|
token_endpoint = get_config(conn, :token_endpoint)
|
|
|
|
supported_scopes = get_config(conn, :scopes)
|
|
|
|
hostname = get_config(conn, :hostname)
|
|
|
|
user_agent = get_config(conn, :user_agent)
|
|
|
|
token_handler = get_config(conn, :token_handler)
|
|
|
|
|
|
|
|
with {:ok, access_token, conn} <- Parser.get_access_token(conn),
|
|
|
|
{:ok, query} <- Parser.get_query(conn),
|
|
|
|
:ok <-
|
|
|
|
token_handler.verify(
|
|
|
|
access_token,
|
|
|
|
token_endpoint,
|
|
|
|
"source",
|
|
|
|
supported_scopes,
|
|
|
|
hostname,
|
|
|
|
user_agent
|
|
|
|
) do
|
|
|
|
Handler.handle_query(query, access_token, conn)
|
2018-03-20 05:17:02 +00:00
|
|
|
else
|
2024-11-29 09:39:35 +00:00
|
|
|
error -> Response.send_error(conn, error)
|
2018-03-20 05:17:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
post "/media" do
|
2024-11-29 09:39:35 +00:00
|
|
|
handler = get_config(conn, :handler)
|
|
|
|
token_endpoint = get_config(conn, :token_endpoint)
|
|
|
|
supported_scopes = get_config(conn, :scopes)
|
|
|
|
hostname = get_config(conn, :hostname)
|
|
|
|
user_agent = get_config(conn, :user_agent)
|
|
|
|
token_handler = get_config(conn, :token_handler)
|
|
|
|
|
|
|
|
with {:ok, access_token, conn} <- Parser.get_access_token(conn),
|
|
|
|
{:ok, file} <- Parser.get_file(conn),
|
|
|
|
{:ok, url} <- handler.handle_media(file, access_token),
|
|
|
|
:ok <-
|
|
|
|
token_handler.verify(
|
|
|
|
access_token,
|
|
|
|
token_endpoint,
|
|
|
|
"media",
|
|
|
|
supported_scopes,
|
|
|
|
hostname,
|
|
|
|
user_agent
|
|
|
|
) do
|
2018-03-20 05:17:02 +00:00
|
|
|
conn
|
|
|
|
|> put_resp_header("location", url)
|
|
|
|
|> send_resp(:created, "")
|
|
|
|
else
|
2024-11-29 09:39:35 +00:00
|
|
|
error -> Response.send_error(conn, error)
|
2018-03-20 05:17:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-04-12 05:50:37 +00:00
|
|
|
match _ do
|
2024-11-29 09:39:35 +00:00
|
|
|
Response.send_error(conn, {:error, :invalid_request, "Request did not match any route."})
|
2018-03-20 05:17:02 +00:00
|
|
|
end
|
|
|
|
|
2024-11-29 09:39:35 +00:00
|
|
|
defp get_config(conn, name) do
|
|
|
|
conn.private[:plug_micropub][name]
|
2018-03-20 05:17:02 +00:00
|
|
|
end
|
|
|
|
end
|