diff --git a/config/config.exs b/config/config.exs index cce2782..2a1686f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -63,9 +63,8 @@ config :phoenix, :json_library, Jason config :annot_at, AnnotAt.Latch, name: AnnotAt.Latch, store: AnnotAt.LatchStore, - mode: :confidential, + mode: :localhost, client_name: "annot.at", - client_id_path: "/oauth-client-metadata.json", redirect_uri_path: "/auth/callback", base_url_fun: &AnnotAtWeb.Endpoint.url/0, scope: @@ -78,9 +77,7 @@ config :annot_at, AnnotAt.Latch, "blob:image/*" ], " " - ), - signing_key: - ~s({"crv":"P-256","d":"h0MvqcXLcKqWZFnqUCAuc6Bmt6gGzj5F5sFOCaUD4Jw","kty":"EC","x":"u0_K5EPDBIlGVp_rUUKucDviS-Owhiv4jnpMCeI7ojY","y":"v_XGrdUIww1wsRA7TUqMWIAJXmi2V8mnoF24Vg5OkvQ"}) + ) config :annot_at, AnnotAt.Vault, ciphers: [ diff --git a/config/dev.exs b/config/dev.exs index 5b32a8e..2825981 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -17,7 +17,7 @@ config :annot_at, AnnotAt.Repo, # watchers to your application. For example, we can use it # to bundle .js and .css sources. config :annot_at, AnnotAtWeb.Endpoint, - url: [host: "tlaloc.haddock-carp.ts.net", scheme: "https", port: 443], + url: [host: "127.0.0.1", scheme: "http", port: 4002], # Binding to loopback ipv4 address prevents access from other machines. # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. http: [ip: {127, 0, 0, 1}], diff --git a/config/prod.exs b/config/prod.exs index a747ead..0579064 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -30,3 +30,10 @@ config :logger, level: :info # Runtime production configuration, including reading # of environment variables, is done on config/runtime.exs. +# +config :annot_at, AnnotAt.Latch, + mode: :confidential, + client_name: "annot.at", + client_id_path: "/oauth-client-metadata.json", + redirect_uri_path: "/auth/callback", + base_url_fun: &AnnotAtWeb.Endpoint.url/0 diff --git a/lib/annot_at/atproto/dns.ex b/lib/annot_at/atproto/dns.ex deleted file mode 100644 index 58ae7c3..0000000 --- a/lib/annot_at/atproto/dns.ex +++ /dev/null @@ -1,23 +0,0 @@ -defmodule AnnotAt.Atproto.DNS do - @moduledoc """ - DNS transport boundary for atproto handle resolution. - - Wraps Erlang's `:inet_res` so this looks more Elixiry. Stubbed - via Mimic in tests, this module has no unit tests of its own. - """ - - @doc """ - Looks up TXT records for `name`, returning each record as a single string. - - A TXT record can arrive as multiple character-strings, they are concatenated - per record. Returns an empty list when there are no records or the lookups - fails, which callers treat as "no DNS answer". - """ - @spec lookup_txt(String.t()) :: [String.t()] - def lookup_txt(name) do - name - |> String.to_charlist() - |> :inet_res.lookup(:in, :txt) - |> Enum.map(&List.to_string/1) - end -end diff --git a/lib/annot_at/atproto/identity.ex b/lib/annot_at/atproto/identity.ex deleted file mode 100644 index f59e248..0000000 --- a/lib/annot_at/atproto/identity.ex +++ /dev/null @@ -1,42 +0,0 @@ -defmodule AnnotAt.Atproto.Identity do - @moduledoc """ - Resolves an atproto handle to a verified identity. - - Resolution is bidirectional per the atproto identity spec, the handle is - resolved to a DID and the DID document is fetched independently, and the - docment's claimed handle must match the handle we started from. Neither - direction alone is trusted, otherwise anyone could point DNS at a victim's - DID. - """ - - alias AnnotAt.Atproto.HTTP - alias Latch.DIDDocument - - @plc_directory "https://plc.directory" - - @enforce_keys [:did, :handle, :pds_endpoint] - defstruct @enforce_keys - - @type t :: %__MODULE__{ - did: String.t(), - handle: String.t(), - pds_endpoint: String.t() - } - - @spec resolve_did(String.t()) :: {:ok, DIDDocument.t()} | {:error, term()} - def resolve_did(did) when is_binary(did) do - with {:ok, doc} <- did_to_document(did) do - DIDDocument.parse(doc, did) - end - end - - defp did_to_document("did:plc:" <> _ = did) do - HTTP.get_json(@plc_directory <> "/" <> did) - end - - defp did_to_document("did:web:" <> host) do - HTTP.get_json("https://" <> URI.decode(host) <> "/.well-known/did.json") - end - - defp did_to_document(_), do: {:error, :unsupported_did_method} -end diff --git a/lib/annot_at/atproto/standard_site.ex b/lib/annot_at/atproto/standard_site.ex index 2b6b405..2ed01c5 100644 --- a/lib/annot_at/atproto/standard_site.ex +++ b/lib/annot_at/atproto/standard_site.ex @@ -6,7 +6,6 @@ defmodule AnnotAt.Atproto.StandardSite do alias AnnotAt.Accounts alias AnnotAt.Atproto.HTTP - alias AnnotAt.Atproto.Identity alias AnnotAt.Atproto.StandardSite.Document alias AnnotAt.Atproto.StandardSite.Publication @@ -164,7 +163,7 @@ defmodule AnnotAt.Atproto.StandardSite do def get_public_publication(_site), do: {:error, :no_publication} def get_public_record(did, collection, rkey) do - with {:ok, did_doc} <- Identity.resolve_did(did), + with {:ok, did_doc} <- Latch.resolve_did(Latch.Shelf, did), url = record_url(did_doc.pds_endpoint, did, collection, rkey), {:ok, %{"value" => value}} <- HTTP.get_json(url) do {:ok, value, did_doc} diff --git a/mix.lock b/mix.lock index 34a0d37..591b0eb 100644 --- a/mix.lock +++ b/mix.lock @@ -26,7 +26,7 @@ "jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"}, "jose": {:hex, :jose, "1.11.12", "06e62b467b61d3726cbc19e9b5489f7549c37993de846dfb3ee8259f9ed208b3", [:mix, :rebar3], [], "hexpm", "31e92b653e9210b696765cdd885437457de1add2a9011d92f8cf63e4641bab7b"}, "kday": {:hex, :kday, "1.1.0", "64efac85279a12283eaaf3ad6f13001ca2dff943eda8c53288179775a8c057a0", [:mix], [{:ex_doc, "~> 0.21", [hex: :ex_doc, repo: "hexpm", optional: true]}], "hexpm", "69703055d63b8d5b260479266c78b0b3e66f7aecdd2022906cd9bf09892a266d"}, - "latch": {:hex, :latch, "0.6.0", "a67dd0e58cfa565b0b7d0d2b6b7f6de10fff158dbed335fa5d5800a0e39344e4", [:mix], [{:finch, "~> 0.23", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.7", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "05870348655fcdcf32d46d8ac8c0ff50816739f8fd34000ad4c6c15204a11d55"}, + "latch": {:hex, :latch, "0.7.0", "ab56e394f15ac655ff44382f6f08292b835b19172c53c3f89ec29bd252eded23", [:mix], [{:finch, "~> 0.23", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.7", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "3b686b52a2d00eb8c03ba039072cace2442d249f35d3b418a769b89e60268fac"}, "lazy_html": {:hex, :lazy_html, "0.1.12", "31a55ee622918fce988c94b06232227b42daa64e4eab14ac32081d0f3fd8db6f", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.9", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:fine, "~> 0.1.0", [hex: :fine, repo: "hexpm", optional: false]}], "hexpm", "8a0da594776caee58782c6f93b2abaa5bdb809daf8d43351a561f7de9dc2e2a8"}, "logger_json": {:hex, :logger_json, "7.0.4", "e315f2b9a755504658a745f3eab90d88d2cd7ac2ecfd08c8da94d8893965ab5c", [:mix], [{:decimal, ">= 0.0.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:ecto, "~> 3.11", [hex: :ecto, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "d1369f8094e372db45d50672c3b91e8888bcd695fdc444a37a0734e96717c45c"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, @@ -50,7 +50,7 @@ "req": {:hex, :req, "0.7.3", "b141f1b465dabc5fb8ce67bd2f15a85fc80f6c75719910699560e32ce49f62ef", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:finch, "~> 0.21", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "73b303030dccc2b6d023ee5ada380825ab3a7cd3863aead493db09ec420ffdf2"}, "saxy": {:hex, :saxy, "1.6.1", "742eff28f553c066d0b54e84662dbf384a1d1f38595472ed15f6e0a33038bbe1", [:mix], [], "hexpm", "8989d504424ba29460a61950f8968380651413fa05e63b6118084db057da1a6b"}, "sentry": {:hex, :sentry, "13.5.0", "d7f6e8d2744036147e53f852d06ee286fdb3842550ab83604b7e20f8a267799f", [:mix], [{:finch, "~> 0.21", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, ">= 1.8.0 and < 5.0.0", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:opentelemetry, ">= 0.0.0", [hex: :opentelemetry, repo: "hexpm", optional: true]}, {:opentelemetry_api, ">= 0.0.0", [hex: :opentelemetry_api, repo: "hexpm", optional: true]}, {:opentelemetry_exporter, ">= 0.0.0", [hex: :opentelemetry_exporter, repo: "hexpm", optional: true]}, {:opentelemetry_semantic_conventions, ">= 0.0.0", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "401ee4b3f58ee62055e6c51fa046c14be129f83346bf07c15775515d4ad246ea"}, - "swoosh": {:hex, :swoosh, "1.27.1", "ca5c1e4a4914c6d1d73d17aaefc3ed53e96edf6b84e0cca03620652ef689cf9d", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, ">= 1.9.0 and < 5.0.0", [hex: :hackney, repo: "hexpm", optional: true]}, {:idna, ">= 6.0.0 and < 8.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9e732f469259e5e84364967b6e0b5d5562adf35bd77576b92a6f3753de6ae9e1"}, + "swoosh": {:hex, :swoosh, "1.28.0", "30d9f3519a150128e90d97f9878a8a5cd8325ed03d618d1c626201496fc20baf", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, ">= 1.9.0 and < 5.0.0", [hex: :hackney, repo: "hexpm", optional: true]}, {:idna, ">= 6.0.0 and < 8.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bb5c0b7c988beb53786254a61580597fe1017a652039061ee2b4c28b5097b10e"}, "tailwind": {:hex, :tailwind, "0.5.1", "35435b13158c90d37da11e1cfc808755fca1d7b6c5ab87b1b19c5de87e2f0a10", [:mix], [], "hexpm", "c4e26302a59fec72abc5610ecb6ad2116d9aa31f31aab2d4b8eb6e95d25a689c"}, "telemetry": {:hex, :telemetry, "1.4.2", "a0cb522801dffb1c49fe6e30561badffc7b6d0e180db1300df759faa22062855", [:rebar3], [], "hexpm", "928f6495066506077862c0d1646609eed891a4326bee3126ba54b60af61febb1"}, "telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"}, diff --git a/test/annot_at_web/controllers/auth_controller_test.exs b/test/annot_at_web/controllers/auth_controller_test.exs index 05f2e9d..15e10c6 100644 --- a/test/annot_at_web/controllers/auth_controller_test.exs +++ b/test/annot_at_web/controllers/auth_controller_test.exs @@ -11,14 +11,9 @@ defmodule AnnotAtWeb.AuthControllerTest do conn = get(conn, ~p"/oauth-client-metadata.json") metadata = json_response(conn, 200) - assert "http://localhost:4002/oauth-client-metadata.json" == metadata["client_id"] assert ["http://localhost:4002/auth/callback"] == metadata["redirect_uris"] assert metadata["scope"] =~ "atproto" assert true == metadata["dpop_bound_access_tokens"] - assert "private_key_jwt" == metadata["token_endpoint_auth_method"] - - assert [key] = metadata["jwks"]["keys"] - refute Map.has_key?(key, "d") end test "GET /auth/callback logs in and redirects dashboard", %{conn: conn} do diff --git a/test/annot_at_web/controllers/public_post_controller_test.exs b/test/annot_at_web/controllers/public_post_controller_test.exs index 585ce94..0fc9531 100644 --- a/test/annot_at_web/controllers/public_post_controller_test.exs +++ b/test/annot_at_web/controllers/public_post_controller_test.exs @@ -4,13 +4,12 @@ defmodule AnnotAtWeb.PublicPostControllerTest do alias AnnotAt.Atproto.StandardSite alias AnnotAt.Atproto.StandardSite.Document - alias Latch.DIDDocument @did "did:plc:ewvi7nxzyoun6zhxrhs64oiz" @rkey "3mlhhbujc22gw" test "GET /p/:did/rkey renders the document", %{conn: conn} do - did_doc = %DIDDocument{did: @did, handle: "jola.dev", pds_endpoint: "https://pds.example"} + did_doc = %{did: @did, handle: "jola.dev", pds_endpoint: "https://pds.example"} doc = %Document{ rkey: @rkey, diff --git a/test/test_helper.exs b/test/test_helper.exs index f15a8cb..e002198 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,3 @@ -Mimic.copy(AnnotAt.Atproto.DNS) Mimic.copy(AnnotAt.Atproto.Directory) Mimic.copy(AnnotAt.Atproto.HTTP) Mimic.copy(AnnotAt.Atproto.Profile)