Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ RUN mix deps.get
RUN mix deps.compile

# build project
COPY priv priv
COPY lib lib
RUN mix compile

Expand Down
8 changes: 0 additions & 8 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import Config

config :hexdocs,
scheme: "http",
port: "4002",
hexpm_url: "http://localhost:4000",
hexpm_secret: "2cd6d09334d4b00a2be4d532342b799b",
# OAuth client credentials for hexpm integration
oauth_client_id: "hexdocs",
oauth_client_secret: "dev_secret_for_testing",
typesense_url: "http://localhost:8108",
typesense_api_key: "hexdocs",
typesense_collection: "hexdocs",
Expand All @@ -21,9 +16,6 @@ config :hexdocs,
queue_id: "test",
queue_producer: Broadway.DummyProducer,
queue_concurrency: 1,
session_key_base: "9doqKjmNsklcWmv1+779E2su++ejdBhnSYgqAiGgwtAPpdVf4ns5eXi4IOZk1Eoi",
session_signing_salt: "QftsNdJO",
session_encryption_salt: "QftsNdJO",
host: "localhost",
private_host: "localhost",
gcs_put_debounce: 0,
Expand Down
1 change: 0 additions & 1 deletion config/dev.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Config

config :hexdocs,
port: "4002",
hexpm_url: "http://localhost:4000",
hexpm_impl: Hexdocs.Hexpm.Impl,
store_impl: Hexdocs.Store.Local,
Expand Down
2 changes: 0 additions & 2 deletions config/prod.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Config

config :hexdocs,
scheme: "https",
hexpm_impl: Hexdocs.Hexpm.Impl,
store_impl: Hexdocs.Store.Impl,
cdn_impl: Hexdocs.CDN.Fastly,
Expand All @@ -23,4 +22,3 @@ config :sentry,
config :sasl, sasl_error_logger: false

config :logger, level: :info
config :logger, :default_formatter, metadata: [:request_id]
6 changes: 0 additions & 6 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@ import Config

if config_env() == :prod do
config :hexdocs,
port: System.fetch_env!("HEXDOCS_PORT"),
hexpm_url: System.fetch_env!("HEXDOCS_HEXPM_URL"),
hexpm_secret: System.fetch_env!("HEXDOCS_HEXPM_SECRET"),
oauth_client_id: System.fetch_env!("HEXDOCS_OAUTH_CLIENT_ID"),
oauth_client_secret: System.fetch_env!("HEXDOCS_OAUTH_CLIENT_SECRET"),
typesense_url: System.fetch_env!("HEXDOCS_TYPESENSE_URL"),
typesense_api_key: System.fetch_env!("HEXDOCS_TYPESENSE_API_KEY"),
typesense_collection: System.fetch_env!("HEXDOCS_TYPESENSE_COLLECTION"),
fastly_key: System.fetch_env!("HEXDOCS_FASTLY_KEY"),
fastly_hexdocs: System.fetch_env!("HEXDOCS_FASTLY_HEXDOCS"),
fastly_hexdocs_private: System.fetch_env!("HEXDOCS_FASTLY_HEXDOCS_PRIVATE"),
queue_id: System.fetch_env!("HEXDOCS_QUEUE_ID"),
session_key_base: System.fetch_env!("HEXDOCS_SESSION_KEY_BASE"),
session_signing_salt: System.fetch_env!("HEXDOCS_SESSION_SIGNING_SALT"),
session_encryption_salt: System.fetch_env!("HEXDOCS_SESSION_ENCRYPTION_SALT"),
queue_concurrency: String.to_integer(System.fetch_env!("HEXDOCS_QUEUE_CONCURRENCY")),
github_user: System.fetch_env!("HEXDOCS_GITHUB_USER"),
github_token: System.fetch_env!("HEXDOCS_GITHUB_TOKEN"),
Expand Down
1 change: 0 additions & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Config

config :hexdocs,
port: "5002",
hexpm_url: "http://localhost:5000",
hexpm_impl: Hexdocs.HexpmMock,
store_impl: Hexdocs.Store.Local,
Expand Down
15 changes: 4 additions & 11 deletions lib/hexdocs/application.ex
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
defmodule Hexdocs.Application do
use Application

require Logger

def start(_type, _args) do
setup_tmp_dir()
:logger.add_handler(:sentry_handler, Sentry.LoggerHandler, %{})

port = String.to_integer(Application.get_env(:hexdocs, :port))
bandit_options = [plug: Hexdocs.Plug, port: port]
Logger.info("Running Bandit with #{inspect(bandit_options)}")

children = [
Hexdocs.TmpDir,
{Task.Supervisor, name: Hexdocs.Tasks},
{Hexdocs.Debouncer, name: Hexdocs.Debouncer},
goth_spec(),
{Bandit, bandit_options},
Hexdocs.Queue
]

Expand All @@ -25,10 +18,10 @@ defmodule Hexdocs.Application do
end

def sentry_before_send(%Sentry.Event{original_exception: exception} = event) do
cond do
Plug.Exception.status(exception) < 500 -> nil
Sentry.DefaultEventFilter.exclude_exception?(exception, event.source) -> nil
true -> event
if Sentry.DefaultEventFilter.exclude_exception?(exception, event.source) do
nil
else
event
end
end

Expand Down
3 changes: 0 additions & 3 deletions lib/hexdocs/hexpm/hexpm.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
defmodule Hexdocs.Hexpm do
@callback verify_key(key :: String.t(), organization :: String.t()) ::
:ok | :refresh | {:error, reason :: String.t()}
@callback get_package(repo :: String.t(), package :: String.t()) :: map() | nil
@callback hexdocs_sitemap() :: binary()

defp impl(), do: Application.get_env(:hexdocs, :hexpm_impl)

def verify_key(key, organization), do: impl().verify_key(key, organization)
def get_package(repo, package), do: impl().get_package(repo, package)
def hexdocs_sitemap(), do: impl().hexdocs_sitemap()
end
39 changes: 2 additions & 37 deletions lib/hexdocs/hexpm/impl.ex
Original file line number Diff line number Diff line change
@@ -1,31 +1,6 @@
defmodule Hexdocs.Hexpm.Impl do
@behaviour Hexdocs.Hexpm

@refresh_errors [
"invalid API key",
"API key revoked",
"key not authorized for this action"
]

def verify_key(key, organization) do
url = url("/api/auth?domain=docs&resource=#{organization}")
fun = fn -> Hexdocs.HTTP.get(url, headers(key)) end

case Hexdocs.HTTP.retry("hexpm", url, fun) do
{:ok, status, _headers, _body} when status in 200..299 ->
:ok

{:ok, status, _headers, body} when status in [401, 403] ->
body = JSON.decode!(body)

if body["message"] in @refresh_errors do
:refresh
else
{:error, body["message"]}
end
end
end

def get_package(repo, package) do
key = Application.get_env(:hexdocs, :hexpm_secret)
url = url("/api/repos/#{repo}/packages/#{package}")
Expand Down Expand Up @@ -56,20 +31,10 @@ defmodule Hexdocs.Hexpm.Impl do
Application.get_env(:hexdocs, :hexpm_url) <> path
end

defp headers(key_or_token) do
# Support both legacy API keys and OAuth Bearer tokens
# OAuth tokens are JWTs that start with "eyJ" (base64 of '{"')
# Legacy API keys are shorter hex strings
authorization =
if String.starts_with?(key_or_token, "eyJ") do
"Bearer #{key_or_token}"
else
key_or_token
end

defp headers(key) do
[
{"accept", "application/json"},
{"authorization", authorization}
{"authorization", key}
]
end
end
52 changes: 0 additions & 52 deletions lib/hexdocs/http.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,6 @@ defmodule Hexdocs.HTTP do

require Logger

def head(url, headers) do
case Req.head(url,
headers: headers,
retry: false,
decode_body: false,
receive_timeout: @receive_timeout
) do
{:ok, response} ->
{:ok, response.status, normalize_headers(response.headers)}

{:error, reason} ->
{:error, reason}
end
end

def get(url, headers, opts \\ []) do
timeout = Keyword.get(opts, :receive_timeout, @receive_timeout)

Expand All @@ -37,23 +22,6 @@ defmodule Hexdocs.HTTP do
end
end

def get_stream(url, headers) do
case Req.get(url,
headers: headers,
retry: false,
decode_body: false,
receive_timeout: @receive_timeout,
into: :self
) do
{:ok, response} ->
stream = stream_body(response.body.ref)
{:ok, response.status, normalize_headers(response.headers), stream}

{:error, reason} ->
{:error, reason}
end
end

def put(url, headers, body) do
case Req.put(url,
headers: headers,
Expand Down Expand Up @@ -127,26 +95,6 @@ defmodule Hexdocs.HTTP do
Enum.map(headers, fn {name, values} -> {name, Enum.join(values, ", ")} end)
end

defp stream_body(ref) do
start_fun = fn -> :cont end
after_fun = fn _ -> :ok end

next_fun = fn
:cont ->
receive do
{^ref, {:data, data}} -> {[{:ok, data}], :cont}
{^ref, :done} -> {:halt, :ok}
after
30_000 -> {[{:error, :timeout}], :stop}
end

:stop ->
{:halt, :ok}
end

Stream.resource(start_fun, next_fun, after_fun)
end

def retry(service, url, fun) do
retry(fun, service, url, 0)
end
Expand Down
Loading