mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
devise-compatible sessions
This commit is contained in:
parent
5de52848c6
commit
8ae0853890
11 changed files with 122 additions and 33 deletions
|
@ -13,6 +13,10 @@ config :philomena,
|
||||||
config :philomena,
|
config :philomena,
|
||||||
password_pepper: "dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP"
|
password_pepper: "dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP"
|
||||||
|
|
||||||
|
config :philomena, :pow,
|
||||||
|
user: Philomena.Users.User,
|
||||||
|
repo: Philomena.Repo
|
||||||
|
|
||||||
config :bcrypt_elixir,
|
config :bcrypt_elixir,
|
||||||
log_rounds: 12
|
log_rounds: 12
|
||||||
|
|
||||||
|
|
13
lib/philomena/users/password.ex
Normal file
13
lib/philomena/users/password.ex
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
defmodule Philomena.Users.Password do
|
||||||
|
def hash_pwd_salt(password, opts \\ []) do
|
||||||
|
pepper = Application.get_env(:philomena, :password_pepper)
|
||||||
|
|
||||||
|
Bcrypt.hash_pwd_salt(<<password::binary, pepper::binary>>, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_pass(password, stored_hash) do
|
||||||
|
pepper = Application.get_env(:philomena, :password_pepper)
|
||||||
|
|
||||||
|
Bcrypt.verify_pass(<<password::binary, pepper::binary>>, stored_hash)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,10 +1,17 @@
|
||||||
defmodule Philomena.Users.User do
|
defmodule Philomena.Users.User do
|
||||||
|
alias Philomena.Users.Password
|
||||||
|
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
|
use Pow.Ecto.Schema,
|
||||||
|
password_hash_methods: {&Password.hash_pwd_salt/1, &Password.verify_pass/2}
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
schema "users" do
|
schema "users" do
|
||||||
field :email, :string
|
field :email, :string
|
||||||
field :encrypted_password, :string, default: ""
|
field :encrypted_password, :string
|
||||||
|
field :password_hash, :string, source: :encrypted_password
|
||||||
field :reset_password_token, :string
|
field :reset_password_token, :string
|
||||||
field :reset_password_sent_at, :naive_datetime
|
field :reset_password_sent_at, :naive_datetime
|
||||||
field :remember_created_at, :naive_datetime
|
field :remember_created_at, :naive_datetime
|
||||||
|
@ -13,12 +20,17 @@ defmodule Philomena.Users.User do
|
||||||
field :last_sign_in_at, :naive_datetime
|
field :last_sign_in_at, :naive_datetime
|
||||||
field :current_sign_in_ip, EctoNetwork.INET
|
field :current_sign_in_ip, EctoNetwork.INET
|
||||||
field :last_sign_in_ip, EctoNetwork.INET
|
field :last_sign_in_ip, EctoNetwork.INET
|
||||||
|
field :name, :string
|
||||||
|
|
||||||
|
pow_user_fields()
|
||||||
|
|
||||||
timestamps(inserted_at: :created_at)
|
timestamps(inserted_at: :created_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def changeset(user, attrs) do
|
def changeset(user, attrs) do
|
||||||
user
|
user
|
||||||
|
|> pow_changeset(attrs)
|
||||||
|> cast(attrs, [])
|
|> cast(attrs, [])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,6 +35,7 @@ defmodule PhilomenaWeb do
|
||||||
|
|
||||||
# Import convenience functions from controllers
|
# Import convenience functions from controllers
|
||||||
import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]
|
import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]
|
||||||
|
import Pow.Plug, only: [current_user: 1]
|
||||||
|
|
||||||
# Use all HTML functionality (forms, tags, etc)
|
# Use all HTML functionality (forms, tags, etc)
|
||||||
use Phoenix.HTML
|
use Phoenix.HTML
|
||||||
|
|
|
@ -43,6 +43,8 @@ defmodule PhilomenaWeb.Endpoint do
|
||||||
signing_salt: "signed cookie",
|
signing_salt: "signed cookie",
|
||||||
encryption_salt: "authenticated encrypted cookie"
|
encryption_salt: "authenticated encrypted cookie"
|
||||||
|
|
||||||
|
plug Philomena.Plugs.Session, otp_app: :philomena
|
||||||
|
|
||||||
plug PhilomenaWeb.Plugs.RenderTime
|
plug PhilomenaWeb.Plugs.RenderTime
|
||||||
plug PhilomenaWeb.Router
|
plug PhilomenaWeb.Router
|
||||||
end
|
end
|
||||||
|
|
52
lib/philomena_web/plugs/session.ex
Normal file
52
lib/philomena_web/plugs/session.ex
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
defmodule Philomena.Plugs.Session do
|
||||||
|
use Pow.Plug.Base
|
||||||
|
|
||||||
|
alias Plug.Conn
|
||||||
|
alias Philomena.{Repo, Users.User}
|
||||||
|
|
||||||
|
@session_key :philomena_session
|
||||||
|
|
||||||
|
def fetch(conn, _config) do
|
||||||
|
conn = Conn.fetch_session(conn)
|
||||||
|
user = Conn.get_session(conn, @session_key)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> maybe_load_user(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(conn, user, _config) do
|
||||||
|
user = session_value(user)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> Conn.fetch_session()
|
||||||
|
|> Conn.put_session(@session_key, user)
|
||||||
|
|
||||||
|
{conn, user}
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, _config) do
|
||||||
|
conn
|
||||||
|
|> Conn.fetch_session()
|
||||||
|
|> Conn.delete_session(@session_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp maybe_load_user(conn, {:ok, user}) do
|
||||||
|
with {:ok, [user_id, hash]} <- Jason.decode(user),
|
||||||
|
%User{} = user <- Repo.get(User, user_id),
|
||||||
|
^hash <- binary_part(user.encrypted_password, 0, 25)
|
||||||
|
do
|
||||||
|
{conn, user}
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
{conn, nil}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defp maybe_load_user(conn, _) do
|
||||||
|
{conn, nil}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp session_value(user) do
|
||||||
|
Jason.encode([user.id, binary_part(user.encrypted_password, 0, 25)])
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,6 @@
|
||||||
defmodule PhilomenaWeb.Router do
|
defmodule PhilomenaWeb.Router do
|
||||||
use PhilomenaWeb, :router
|
use PhilomenaWeb, :router
|
||||||
|
use Pow.Phoenix.Router
|
||||||
|
|
||||||
pipeline :browser do
|
pipeline :browser do
|
||||||
plug :accepts, ["html"]
|
plug :accepts, ["html"]
|
||||||
|
@ -13,6 +14,12 @@ defmodule PhilomenaWeb.Router do
|
||||||
plug :accepts, ["json"]
|
plug :accepts, ["json"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scope "/" do
|
||||||
|
pipe_through :browser
|
||||||
|
|
||||||
|
pow_routes()
|
||||||
|
end
|
||||||
|
|
||||||
scope "/", PhilomenaWeb do
|
scope "/", PhilomenaWeb do
|
||||||
pipe_through :browser
|
pipe_through :browser
|
||||||
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
||||||
<title>Philomena · Phoenix Framework</title>
|
|
||||||
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<section class="container">
|
|
||||||
<nav role="navigation">
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
<a href="http://phoenixframework.org/" class="phx-logo">
|
|
||||||
<img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" alt="Phoenix Framework Logo"/>
|
|
||||||
</a>
|
|
||||||
</section>
|
|
||||||
</header>
|
|
||||||
<main role="main" class="container">
|
|
||||||
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
|
|
||||||
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
|
|
||||||
<%= render @view_module, @view_template, assigns %>
|
|
||||||
<p>Rendered in <%= render_time(@conn) %> ms</p>
|
|
||||||
</main>
|
|
||||||
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
24
lib/philomena_web/templates/layout/app.html.slime
Normal file
24
lib/philomena_web/templates/layout/app.html.slime
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
doctype html
|
||||||
|
html lang="en"
|
||||||
|
head
|
||||||
|
meta charset="utf-8"
|
||||||
|
meta http-equiv="X-UA-Compatible" content="IE=edge"
|
||||||
|
meta name="viewport" content="width=device-width, initial-scale=1.0"
|
||||||
|
title
|
||||||
|
= if assigns[:title] do
|
||||||
|
=> assigns[:title]
|
||||||
|
' - Philomena
|
||||||
|
- else
|
||||||
|
' Philomena
|
||||||
|
link rel="stylesheet" href=Routes.static_path(@conn, "/css/app.css")
|
||||||
|
body
|
||||||
|
= if @current_user do
|
||||||
|
p
|
||||||
|
' Welcome
|
||||||
|
= @current_user.name
|
||||||
|
= render @view_module, @view_template, assigns
|
||||||
|
p
|
||||||
|
' Rendered in
|
||||||
|
=> render_time(@conn)
|
||||||
|
' ms
|
||||||
|
script type="text/javascript" src=Routes.static_path(@conn, "/js/app.js")
|
3
mix.exs
3
mix.exs
|
@ -45,7 +45,8 @@ defmodule Philomena.MixProject do
|
||||||
{:plug_cowboy, "~> 2.0"},
|
{:plug_cowboy, "~> 2.0"},
|
||||||
{:phoenix_slime, "~> 0.12.0"},
|
{:phoenix_slime, "~> 0.12.0"},
|
||||||
{:ecto_network, "~> 1.1"},
|
{:ecto_network, "~> 1.1"},
|
||||||
{:pbkdf2, "~> 2.0"}
|
{:pow, "~> 1.0.11"},
|
||||||
|
{:bcrypt_elixir, "~> 2.0"}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
4
mix.lock
4
mix.lock
|
@ -1,4 +1,6 @@
|
||||||
%{
|
%{
|
||||||
|
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.0.3", "64e0792d5b5064391927bf3b8e436994cafd18ca2d2b76dea5c76e0adcf66b7c", [:make, :mix], [{:comeonin, "~> 5.1", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
|
"comeonin": {:hex, :comeonin, "5.1.2", "fbbbbbfcf0f0e9900c0336d16c8d462edf838ba1759577e29cc5fbd7c28a4540", [:mix], [], "hexpm"},
|
||||||
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
|
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
|
||||||
"cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
|
"cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"},
|
"cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"},
|
||||||
|
@ -7,6 +9,7 @@
|
||||||
"ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
|
"ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"ecto_network": {:hex, :ecto_network, "1.1.0", "7062004b9324ff13e50c02dab84877f8a55e06db9eabbf2d04bda21da6fc6e8a", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm"},
|
"ecto_network": {:hex, :ecto_network, "1.1.0", "7062004b9324ff13e50c02dab84877f8a55e06db9eabbf2d04bda21da6fc6e8a", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
|
"ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
|
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"},
|
||||||
"file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"},
|
"file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"},
|
||||||
"gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
|
"gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
|
||||||
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
|
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
|
@ -23,6 +26,7 @@
|
||||||
"plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
"plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
|
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
|
||||||
"postgrex": {:hex, :postgrex, "0.15.0", "dd5349161019caeea93efa42f9b22f9d79995c3a86bdffb796427b4c9863b0f0", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
|
"postgrex": {:hex, :postgrex, "0.15.0", "dd5349161019caeea93efa42f9b22f9d79995c3a86bdffb796427b4c9863b0f0", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
|
"pow": {:hex, :pow, "1.0.11", "f5ef721ac17d2bf8f9dd92f5d40fa0b96512d24b91a26603147754034e3a6101", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3.0 or ~> 1.4.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
|
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
|
||||||
"slime": {:hex, :slime, "1.2.0", "d46ede53c96b743dfdd23821268dc9b01f04ffea65d9d57c4e3d9200b162df02", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm"},
|
"slime": {:hex, :slime, "1.2.0", "d46ede53c96b743dfdd23821268dc9b01f04ffea65d9d57c4e3d9200b162df02", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
|
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
|
||||||
|
|
Loading…
Reference in a new issue