aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Braun <roger@rogerbraun.net>2017-09-06 19:06:25 +0200
committerRoger Braun <roger@rogerbraun.net>2017-09-06 19:06:25 +0200
commit2a298d70f9938d1b6d5af04d8b8863fdd3299f46 (patch)
tree7029989860d19246a0840a7991db46ad5b3207df
parent4e785df984bed0e2ffc3f5a773a961ed3efd4760 (diff)
downloadpleroma-2a298d70f9938d1b6d5af04d8b8863fdd3299f46.tar.gz
Add very basic oauth and mastodon api support.
-rw-r--r--lib/pleroma/app.ex29
-rw-r--r--lib/pleroma/plugs/oauth_plug.ex22
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api.ex0
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex32
-rw-r--r--lib/pleroma/web/oauth/authorization.ex30
-rw-r--r--lib/pleroma/web/oauth/oauth_controller.ex44
-rw-r--r--lib/pleroma/web/oauth/oauth_view.ex4
-rw-r--r--lib/pleroma/web/oauth/token.ex31
-rw-r--r--lib/pleroma/web/router.ex18
-rw-r--r--lib/pleroma/web/templates/layout/app.html.eex11
-rw-r--r--lib/pleroma/web/templates/o_auth/o_auth/results.html.eex2
-rw-r--r--lib/pleroma/web/templates/o_auth/o_auth/show.html.eex14
-rw-r--r--lib/pleroma/web/views/layout_view.ex3
-rw-r--r--priv/repo/migrations/20170906120646_add_mastodon_apps.exs16
-rw-r--r--priv/repo/migrations/20170906143140_create_o_auth_authorizations.exs15
-rw-r--r--priv/repo/migrations/20170906152508_create_o_auth_token.exs15
16 files changed, 286 insertions, 0 deletions
diff --git a/lib/pleroma/app.ex b/lib/pleroma/app.ex
new file mode 100644
index 000000000..d467595ea
--- /dev/null
+++ b/lib/pleroma/app.ex
@@ -0,0 +1,29 @@
+defmodule Pleroma.App do
+ use Ecto.Schema
+ import Ecto.{Changeset}
+
+ schema "apps" do
+ field :client_name, :string
+ field :redirect_uris, :string
+ field :scopes, :string
+ field :website, :string
+ field :client_id, :string
+ field :client_secret, :string
+
+ timestamps()
+ end
+
+ def register_changeset(struct, params \\ %{}) do
+ changeset = struct
+ |> cast(params, [:client_name, :redirect_uris, :scopes, :website])
+ |> validate_required([:client_name, :redirect_uris, :scopes])
+
+ if changeset.valid? do
+ changeset
+ |> put_change(:client_id, :crypto.strong_rand_bytes(32) |> Base.url_encode64)
+ |> put_change(:client_secret, :crypto.strong_rand_bytes(32) |> Base.url_encode64)
+ else
+ changeset
+ end
+ end
+end
diff --git a/lib/pleroma/plugs/oauth_plug.ex b/lib/pleroma/plugs/oauth_plug.ex
new file mode 100644
index 000000000..fc2a907a2
--- /dev/null
+++ b/lib/pleroma/plugs/oauth_plug.ex
@@ -0,0 +1,22 @@
+defmodule Pleroma.Plugs.OAuthPlug do
+ import Plug.Conn
+ alias Pleroma.User
+ alias Pleroma.Repo
+ alias Pleroma.Web.OAuth.Token
+
+ def init(options) do
+ options
+ end
+
+ def call(%{assigns: %{user: %User{}}} = conn, _), do: conn
+ def call(conn, opts) do
+ with ["Bearer " <> header] <- get_req_header(conn, "authorization"),
+ %Token{user_id: user_id} <- Repo.get_by(Token, token: header),
+ %User{} = user <- Repo.get(User, user_id) do
+ conn
+ |> assign(:user, user)
+ else
+ _ -> conn
+ end
+ end
+end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
new file mode 100644
index 000000000..89e37d6ab
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -0,0 +1,32 @@
+defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
+ use Pleroma.Web, :controller
+ alias Pleroma.{Repo, App}
+
+ def create_app(conn, params) do
+ with cs <- App.register_changeset(%App{}, params) |> IO.inspect,
+ {:ok, app} <- Repo.insert(cs) |> IO.inspect do
+ res = %{
+ id: app.id,
+ client_id: app.client_id,
+ client_secret: app.client_secret
+ }
+
+ json(conn, res)
+ end
+ end
+
+ def verify_credentials(%{assigns: %{user: user}} = conn, params) do
+ account = %{
+ id: user.id,
+ username: user.nickname,
+ acct: user.nickname,
+ display_name: user.name,
+ locked: false,
+ created_at: user.inserted_at,
+ note: user.bio,
+ url: ""
+ }
+
+ json(conn, account)
+ end
+end
diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex
new file mode 100644
index 000000000..9423c9632
--- /dev/null
+++ b/lib/pleroma/web/oauth/authorization.ex
@@ -0,0 +1,30 @@
+defmodule Pleroma.Web.OAuth.Authorization do
+ use Ecto.Schema
+
+ alias Pleroma.{App, User, Repo}
+ alias Pleroma.Web.OAuth.Authorization
+
+ schema "oauth_authorizations" do
+ field :token, :string
+ field :valid_until, :naive_datetime
+ field :used, :boolean, default: false
+ belongs_to :user, Pleroma.User
+ belongs_to :app, Pleroma.App
+
+ timestamps()
+ end
+
+ def create_authorization(%App{} = app, %User{} = user) do
+ token = :crypto.strong_rand_bytes(32) |> Base.url_encode64
+
+ authorization = %Authorization{
+ token: token,
+ used: false,
+ user_id: user.id,
+ app_id: app.id,
+ valid_until: NaiveDateTime.add(NaiveDateTime.utc_now, 60 * 10)
+ }
+
+ Repo.insert(authorization)
+ end
+end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
new file mode 100644
index 000000000..f0e091ac2
--- /dev/null
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -0,0 +1,44 @@
+defmodule Pleroma.Web.OAuth.OAuthController do
+ use Pleroma.Web, :controller
+
+ alias Pleroma.Web.OAuth.{Authorization, Token}
+ alias Pleroma.{Repo, User, App}
+ alias Comeonin.Pbkdf2
+
+ def authorize(conn, params) do
+ render conn, "show.html", %{
+ response_type: params["response_type"],
+ client_id: params["client_id"],
+ scope: params["scope"],
+ redirect_uri: params["redirect_uri"]
+ }
+ end
+
+ def create_authorization(conn, %{"authorization" => %{"name" => name, "password" => password, "client_id" => client_id}} = params) do
+ with %User{} = user <- User.get_cached_by_nickname(name),
+ true <- Pbkdf2.checkpw(password, user.password_hash),
+ %App{} = app <- Pleroma.Repo.get_by(Pleroma.App, client_id: client_id),
+ {:ok, auth} <- Authorization.create_authorization(app, user) do
+ render conn, "results.html", %{
+ auth: auth
+ }
+ end
+ end
+
+ # TODO CRITICAL
+ # - Check validity of auth token
+ def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do
+ with %App{} = app <- Repo.get_by(App, client_id: params["client_id"], client_secret: params["client_secret"]),
+ %Authorization{} = auth <- Repo.get_by(Authorization, token: params["code"], app_id: app.id),
+ {:ok, token} <- Token.create_token(app, Repo.get(User, auth.user_id)) do
+ response = %{
+ token_type: "Bearer",
+ access_token: token.token,
+ refresh_token: token.refresh_token,
+ expires_in: 60 * 10,
+ scope: "read write follow"
+ }
+ json(conn, response)
+ end
+ end
+end
diff --git a/lib/pleroma/web/oauth/oauth_view.ex b/lib/pleroma/web/oauth/oauth_view.ex
new file mode 100644
index 000000000..b3923fcf5
--- /dev/null
+++ b/lib/pleroma/web/oauth/oauth_view.ex
@@ -0,0 +1,4 @@
+defmodule Pleroma.Web.OAuth.OAuthView do
+ use Pleroma.Web, :view
+ import Phoenix.HTML.Form
+end
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
new file mode 100644
index 000000000..49e72428c
--- /dev/null
+++ b/lib/pleroma/web/oauth/token.ex
@@ -0,0 +1,31 @@
+defmodule Pleroma.Web.OAuth.Token do
+ use Ecto.Schema
+
+ alias Pleroma.{App, User, Repo}
+ alias Pleroma.Web.OAuth.Token
+
+ schema "oauth_tokens" do
+ field :token, :string
+ field :refresh_token, :string
+ field :valid_until, :naive_datetime
+ belongs_to :user, Pleroma.User
+ belongs_to :app, Pleroma.App
+
+ timestamps()
+ end
+
+ def create_token(%App{} = app, %User{} = user) do
+ token = :crypto.strong_rand_bytes(32) |> Base.url_encode64
+ refresh_token = :crypto.strong_rand_bytes(32) |> Base.url_encode64
+
+ token = %Token{
+ token: token,
+ refresh_token: refresh_token,
+ user_id: user.id,
+ app_id: app.id,
+ valid_until: NaiveDateTime.add(NaiveDateTime.utc_now, 60 * 10)
+ }
+
+ Repo.insert(token)
+ end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index c20ec3e80..6081016d6 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -16,6 +16,7 @@ defmodule Pleroma.Web.Router do
pipeline :authenticated_api do
plug :accepts, ["json"]
plug :fetch_session
+ plug Pleroma.Plugs.OAuthPlug
plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1}
end
@@ -31,10 +32,27 @@ defmodule Pleroma.Web.Router do
plug :accepts, ["json"]
end
+ pipeline :oauth do
+ plug :accepts, ["html", "json"]
+ end
+
+ scope "/oauth", Pleroma.Web.OAuth do
+ get "/authorize", OAuthController, :authorize
+ post "/authorize", OAuthController, :create_authorization
+ post "/token", OAuthController, :token_exchange
+ end
+
scope "/api/v1", Pleroma.Web do
pipe_through :masto_config
# TODO: Move this
get "/instance", TwitterAPI.UtilController, :masto_instance
+ post "/apps", MastodonAPI.MastodonAPIController, :create_app
+ end
+
+ scope "/api/v1", Pleroma.Web.MastodonAPI do
+ pipe_through :authenticated_api
+
+ get "/accounts/verify_credentials", MastodonAPIController, :verify_credentials
end
scope "/api", Pleroma.Web do
diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex
new file mode 100644
index 000000000..6cc3b7ac5
--- /dev/null
+++ b/lib/pleroma/web/templates/layout/app.html.eex
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset=utf-8 />
+ <title>Pleroma</title>
+ </head>
+ <body>
+ <h1>Welcome to Pleroma</h1>
+ <%= render @view_module, @view_template, assigns %>
+ </body>
+</html>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/results.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/results.html.eex
new file mode 100644
index 000000000..8443d906b
--- /dev/null
+++ b/lib/pleroma/web/templates/o_auth/o_auth/results.html.eex
@@ -0,0 +1,2 @@
+<h1>Successfully authorized</h1>
+<h2>Token code is <%= @auth.token %></h2>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
new file mode 100644
index 000000000..ce295ed05
--- /dev/null
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -0,0 +1,14 @@
+<h2>OAuth Authorization</h2>
+<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
+<%= label f, :name, "Name" %>
+<%= text_input f, :name %>
+<br>
+<%= label f, :password, "Password" %>
+<%= password_input f, :password %>
+<br>
+<%= hidden_input f, :client_id, value: @client_id %>
+<%= hidden_input f, :response_type, value: @response_type %>
+<%= hidden_input f, :redirect_uri, value: @redirect_uri %>
+<%= hidden_input f, :scope, value: @scope %>
+<%= submit "Authorize" %>
+<% end %>
diff --git a/lib/pleroma/web/views/layout_view.ex b/lib/pleroma/web/views/layout_view.ex
new file mode 100644
index 000000000..d4d4c3bd3
--- /dev/null
+++ b/lib/pleroma/web/views/layout_view.ex
@@ -0,0 +1,3 @@
+defmodule Pleroma.Web.LayoutView do
+ use Pleroma.Web, :view
+end
diff --git a/priv/repo/migrations/20170906120646_add_mastodon_apps.exs b/priv/repo/migrations/20170906120646_add_mastodon_apps.exs
new file mode 100644
index 000000000..d3dd317dd
--- /dev/null
+++ b/priv/repo/migrations/20170906120646_add_mastodon_apps.exs
@@ -0,0 +1,16 @@
+defmodule Pleroma.Repo.Migrations.AddMastodonApps do
+ use Ecto.Migration
+
+ def change do
+ create table(:apps) do
+ add :client_name, :string
+ add :redirect_uris, :string
+ add :scopes, :string
+ add :website, :string
+ add :client_id, :string
+ add :client_secret, :string
+
+ timestamps()
+ end
+ end
+end
diff --git a/priv/repo/migrations/20170906143140_create_o_auth_authorizations.exs b/priv/repo/migrations/20170906143140_create_o_auth_authorizations.exs
new file mode 100644
index 000000000..b4332870e
--- /dev/null
+++ b/priv/repo/migrations/20170906143140_create_o_auth_authorizations.exs
@@ -0,0 +1,15 @@
+defmodule Pleroma.Repo.Migrations.CreateOAuthAuthorizations do
+ use Ecto.Migration
+
+ def change do
+ create table(:oauth_authorizations) do
+ add :app_id, references(:apps)
+ add :user_id, references(:users)
+ add :token, :string
+ add :valid_until, :naive_datetime
+ add :used, :boolean, default: false
+
+ timestamps()
+ end
+ end
+end
diff --git a/priv/repo/migrations/20170906152508_create_o_auth_token.exs b/priv/repo/migrations/20170906152508_create_o_auth_token.exs
new file mode 100644
index 000000000..7f8550f33
--- /dev/null
+++ b/priv/repo/migrations/20170906152508_create_o_auth_token.exs
@@ -0,0 +1,15 @@
+defmodule Pleroma.Repo.Migrations.CreateOAuthToken do
+ use Ecto.Migration
+
+ def change do
+ create table(:oauth_tokens) do
+ add :app_id, references(:apps)
+ add :user_id, references(:users)
+ add :token, :string
+ add :refresh_token, :string
+ add :valid_until, :naive_datetime
+
+ timestamps()
+ end
+ end
+end