Skip to content

Commit

Permalink
no fun allowed
Browse files Browse the repository at this point in the history
  • Loading branch information
mekaem committed Jul 3, 2024
1 parent 1d0b374 commit 19283c8
Show file tree
Hide file tree
Showing 62 changed files with 375 additions and 335 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ erl_crash.dump
*.ez

# Ignore package tarball (built via "mix hex.build").
hipdster-*.tar
hexpds-*.tar

# Temporary files, for example, from tests.
/tmp/
Expand All @@ -38,3 +38,6 @@ pds-wal

# Cargo build output
/target/

#DS_Store
.DS_Store
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# hipdster
# hexPDS
An ATProto PDS in Elixir/Rust

## The current state of things
Expand Down
22 changes: 12 additions & 10 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Config

# example usage:
#  Application.get_env(:hipdster, :plc_server)
#  Application.get_env(:hexpds, :plc_server)

config :hipdster,
config :hexpds,
plc_server: "plc.directory",
appview_server: "public.api.bsky.app",
relay_server: "bsky.network",
Expand All @@ -13,16 +13,18 @@ config :hipdster,
admin_password: "admin",
# or Ecto.Adapters.Postgres in production
ecto_adapter: Ecto.Adapters.SQLite3,
ecto_repos: [Hipdster.Database],
port: (case Mix.env do
:prod -> 3999
:dev -> 4000
:test -> 4001
end),
ecto_repos: [Hexpds.Database],
port:
(case Mix.env() do
:prod -> 3999
:dev -> 4000
:test -> 4001
end),
# Example HS256 secret for access and refresh JWTs
jwt_key: <<16474290805911645537423060771945528686550823130298449174717469148262408363010::256>>
jwt_key:
<<16_474_290_805_911_645_537_423_060_771_945_528_686_550_823_130_298_449_174_717_469_148_262_408_363_010::256>>

config :hipdster, Hipdster.Database,
config :hexpds, Hexpds.Database,
# Replace with Postgres URL in production!
url: "sqlite3:///pds"

Expand Down
14 changes: 7 additions & 7 deletions lib/hipdster/auth.ex → lib/hexpds/auth.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
defmodule Hipdster.Auth do
defmodule Hexpds.Auth do
@moduledoc """
Authentication and session management
"""
alias Hipdster.User
alias Hexpds.User

def generate_session(_, username, pw) do
if Hipdster.User.authenticate(username, pw) do
Hipdster.User.get(username)
if Hexpds.User.authenticate(username, pw) do
Hexpds.User.get(username)
|> generate_session()
else
%{
Expand All @@ -18,8 +18,8 @@ alias Hipdster.User

def generate_session(%User{handle: handle, did: did} = u) do
%{
accessJwt: Hipdster.Auth.JWT.access_jwt(u, "main"),
refreshJwt: Hipdster.Auth.JWT.refresh_jwt(u, "main"),
accessJwt: Hexpds.Auth.JWT.access_jwt(u, "main"),
refreshJwt: Hexpds.Auth.JWT.refresh_jwt(u, "main"),
handle: handle,
did: did
}
Expand All @@ -28,7 +28,7 @@ alias Hipdster.User
def admin_auth("Basic " <> credentials) do
with {:ok, creds} <- Base.decode64(credentials),
["admin", password] <- String.split(creds, ":") do
Application.get_env(:hipdster, :admin_password) == password
Application.get_env(:hexpds, :admin_password) == password
else
_ -> false
end
Expand Down
27 changes: 13 additions & 14 deletions lib/hipdster/auth/context.ex → lib/hexpds/auth/context.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Hipdster.Auth.Context do
defmodule Hexpds.Auth.Context do
@moduledoc """
A struct containing some context for a request,
such as the currently logged in user, the app password
Expand All @@ -18,7 +18,7 @@ defmodule Hipdster.Auth.Context do

@type t :: %__MODULE__{
authed: boolean(),
user: Hipdster.User.t() | nil,
user: Hexpds.User.t() | nil,
is_app_pwd?: boolean(),
app_password_name: String.t() | nil,
token_type: token_type() | nil
Expand All @@ -28,18 +28,19 @@ defmodule Hipdster.Auth.Context do

def app_pwd?(%__MODULE__{is_app_pwd?: is_app_pwd?}), do: is_app_pwd?

def parse_jwt(jwt, hs256_secret \\ Application.get_env(:hipdster, :jwt_key)) do
Hipdster.Auth.Session.verify(jwt, hs256_secret)
def parse_jwt(jwt, hs256_secret \\ Application.get_env(:hexpds, :jwt_key)) do
Hexpds.Auth.Session.verify(jwt, hs256_secret)
|> json_to_ctx()
end

def unauthed(), do: %__MODULE__{
authed: false,
user: nil,
is_app_pwd?: false,
app_password_name: nil,
token_type: nil
}
def unauthed(),
do: %__MODULE__{
authed: false,
user: nil,
is_app_pwd?: false,
app_password_name: nil,
token_type: nil
}

defp json_to_ctx({:error, _}),
do: unauthed()
Expand All @@ -53,7 +54,7 @@ defmodule Hipdster.Auth.Context do

%__MODULE__{
authed: true,
user: Hipdster.User.get(did),
user: Hexpds.User.get(did),
is_app_pwd?: is_app_pwd,
app_password_name: app_password_name,
token_type: token_type(scope)
Expand All @@ -68,9 +69,7 @@ defmodule Hipdster.Auth.Context do
defp token_type("com.atproto.access"), do: :access
defp token_type("com.atproto.refresh"), do: :refresh


def parse_header(nil), do: unauthed()
def parse_header("Bearer " <> jwt), do: parse_jwt(jwt)
def parse_header(_), do: unauthed()

end
33 changes: 16 additions & 17 deletions lib/hipdster/auth/jwt.ex → lib/hexpds/auth/jwt.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
defmodule Hipdster.Auth.JWT do
defmodule Hexpds.Auth.JWT do
@moduledoc """
JWT generation and verification
"""
defmodule Internal do
@moduledoc false
use Rustler, otp_app: :hipdster, crate: "hipdster_auth_jwt_internal"
use Rustler, otp_app: :hexpds, crate: "hexpds_auth_jwt_internal"

import Hipdster.Helpers
import Hexpds.Helpers

def generate_k256_jwt(_account_did, _service_did, _subject, _key),
do: :erlang.nif_error(:nif_not_loaded)
Expand All @@ -19,21 +19,21 @@ defmodule Hipdster.Auth.JWT do
def verify_hs256_jwt(_jwt, _key), do: :erlang.nif_error(:nif_not_loaded)
end

import Hipdster.Helpers
import Hexpds.Helpers

@spec interservice(Hipdster.User.t(), Hipdster.Identity.did(), String.t()) ::
@spec interservice(Hexpds.User.t(), Hexpds.Identity.did(), String.t()) ::
{:ok, binary()} | {:error, String.t()}
def interservice(
%Hipdster.User{
signing_key: %Hipdster.K256.PrivateKey{
%Hexpds.User{
signing_key: %Hexpds.K256.PrivateKey{
privkey: <<>> <> signing_key_bytes
},
did: user_did
},
service_did,
subject \\ ""
) do
Hipdster.Auth.JWT.Internal.generate_k256_jwt(
Hexpds.Auth.JWT.Internal.generate_k256_jwt(
user_did,
service_did,
subject,
Expand All @@ -45,11 +45,11 @@ defmodule Hipdster.Auth.JWT do
def!(interservice(user, service_did))

def access_jwt(
%Hipdster.User{did: did},
%Hexpds.User{did: did},
app_password_name \\ "main",
hs256_secret \\ Application.get_env(:hipdster, :jwt_key)
hs256_secret \\ Application.get_env(:hexpds, :jwt_key)
) do
Hipdster.Auth.JWT.Internal.generate_hs256_jwt!(
Hexpds.Auth.JWT.Internal.generate_hs256_jwt!(
did,
Jason.encode!(%{scope: "com.atproto.access", pwd: app_password_name}),
hs256_secret,
Expand All @@ -58,20 +58,20 @@ defmodule Hipdster.Auth.JWT do
end

def refresh_jwt(
%Hipdster.User{did: did},
%Hexpds.User{did: did},
app_password_name \\ "main",
hs256_secret \\ Application.get_env(:hipdster, :jwt_key)
hs256_secret \\ Application.get_env(:hexpds, :jwt_key)
) do
Hipdster.Auth.JWT.Internal.generate_hs256_jwt!(
Hexpds.Auth.JWT.Internal.generate_hs256_jwt!(
did,
Jason.encode!(%{scope: "com.atproto.refresh", pwd: app_password_name}),
hs256_secret,
130_000
)
end

def verify(jwt, hs256_secret \\ Application.get_env(:hipdster, :jwt_key)) do
Hipdster.Auth.JWT.Internal.verify_hs256_jwt(jwt, hs256_secret)
def verify(jwt, hs256_secret \\ Application.get_env(:hexpds, :jwt_key)) do
Hexpds.Auth.JWT.Internal.verify_hs256_jwt(jwt, hs256_secret)
|> case do
{:ok, json} ->
Jason.decode!(json)
Expand All @@ -84,5 +84,4 @@ defmodule Hipdster.Auth.JWT do

def is_valid_pwd?("main"), do: true
def is_valid_pwd?(_), do: false

end
23 changes: 13 additions & 10 deletions lib/hipdster/auth/session.ex → lib/hexpds/auth/session.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Hipdster.Auth.Session do
defmodule Hexpds.Auth.Session do
require Matcha

use Memento.Table,
Expand All @@ -9,14 +9,14 @@ defmodule Hipdster.Auth.Session do
@type t :: %__MODULE__{
refresh_jwt: String.t(),
access_jwt: String.t(),
did: Hipdster.Identity.did()
did: Hexpds.Identity.did()
}

def new(uname) do
%{did: did, refreshJwt: r_jwt, accessJwt: a_jwt} =
resp =
Hipdster.User.get(uname)
|> Hipdster.Auth.generate_session()
Hexpds.User.get(uname)
|> Hexpds.Auth.generate_session()

sess = %__MODULE__{refresh_jwt: r_jwt, access_jwt: a_jwt, did: did}

Expand All @@ -28,7 +28,7 @@ defmodule Hipdster.Auth.Session do
end

def new(uname, pw) do
if Hipdster.User.authenticate(uname, pw) do
if Hexpds.User.authenticate(uname, pw) do
new(uname)
end
end
Expand All @@ -51,7 +51,7 @@ defmodule Hipdster.Auth.Session do
__MODULE__,
(Matcha.spec do
{__MODULE__, _, ^jwt, _} = ses -> ses
end).source
end).source
)
end)
|> List.first()
Expand All @@ -69,14 +69,17 @@ defmodule Hipdster.Auth.Session do

def refresh(r_jwt) do
case find_r_jwt(r_jwt) do
nil -> {:error, "Invalid token"}
%{did: did} -> delete(r_jwt)
nil ->
{:error, "Invalid token"}

%{did: did} ->
delete(r_jwt)
new(did)
end
end

def verify(jwt, hs256 \\ Application.get_env(:hipdster, :jwt_key)) do
Hipdster.Auth.JWT.verify(jwt, hs256)
def verify(jwt, hs256 \\ Application.get_env(:hexpds, :jwt_key)) do
Hexpds.Auth.JWT.verify(jwt, hs256)
|> case do
{:error, reason} ->
{:error, reason}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Hipdster.Auth.Session.Cleaner do
defmodule Hexpds.Auth.Session.Cleaner do
@moduledoc """
Deletes expired sessions on the hour
"""
Expand All @@ -20,14 +20,15 @@ defmodule Hipdster.Auth.Session.Cleaner do
Memento.transaction!(fn ->
:mnesia.foldl(
fn {_, r_jwt, _, _}, _ ->
unless Hipdster.Auth.JWT.verify(r_jwt) do
Hipdster.Auth.Session.delete(r_jwt)
unless Hexpds.Auth.JWT.verify(r_jwt) do
Hexpds.Auth.Session.delete(r_jwt)
end
end,
nil,
Hipdster.Auth.Session
Hexpds.Auth.Session
)
end)

{:noreply, state}
end
end
Loading

0 comments on commit 19283c8

Please sign in to comment.