argon2 password hashing (#406)

Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/406
This commit is contained in:
floatingghost 2022-12-30 02:46:58 +00:00
parent a5e98083f2
commit 9be6caf125
25 changed files with 188 additions and 99 deletions

View file

@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Prometheus metrics exporting from `/api/v1/akkoma/metrics`
- Ability to alter http pool size
- Translation of statuses via ArgosTranslate
- Argon2 password hashing
- Ability to "verify" links in profile fields via rel=me
- Mix tasks to dump/load config to/from json for bulk editing
@ -17,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Non-finch HTTP adapters
- Legacy redirect from /api/pleroma/admin to /api/v1/pleroma/admin
- Legacy redirects from /api/pleroma to /api/v1/pleroma
- :crypt dependency
### Changed
- Return HTTP error 413 when uploading an avatar or banner that's above the configured upload limit instead of a 500.

View file

@ -87,13 +87,15 @@ defmodule Mix.Tasks.Pleroma.Config do
key = maybe_atomize(key)
config = ConfigDB.get_by_group_and_key(group, key)
json = %{
group: ConfigDB.to_json_types(config.group),
key: ConfigDB.to_json_types(config.key),
value: ConfigDB.to_json_types(config.value),
}
|> Jason.encode!()
|> Jason.Formatter.pretty_print()
json =
%{
group: ConfigDB.to_json_types(config.group),
key: ConfigDB.to_json_types(config.key),
value: ConfigDB.to_json_types(config.value)
}
|> Jason.encode!()
|> Jason.Formatter.pretty_print()
File.write(fname, json)
shell_info("Wrote #{group}_#{key}.json")

54
lib/pleroma/password.ex Normal file
View file

@ -0,0 +1,54 @@
defmodule Pleroma.Password do
@moduledoc """
This module handles password hashing and verification.
It will delegate to the appropriate module based on the password hash.
It also handles upgrading of password hashes.
"""
alias Pleroma.User
alias Pleroma.Password.Pbkdf2
require Logger
@hashing_module Argon2
@spec hash_pwd_salt(String.t()) :: String.t()
defdelegate hash_pwd_salt(pass), to: @hashing_module
@spec checkpw(String.t(), String.t()) :: boolean()
def checkpw(password, "$2" <> _ = password_hash) do
# Handle bcrypt passwords for Mastodon migration
Bcrypt.verify_pass(password, password_hash)
end
def checkpw(password, "$pbkdf2" <> _ = password_hash) do
Pbkdf2.verify_pass(password, password_hash)
end
def checkpw(password, "$argon2" <> _ = password_hash) do
Argon2.verify_pass(password, password_hash)
end
def checkpw(_password, _password_hash) do
Logger.error("Password hash not recognized")
false
end
@spec maybe_update_password(User.t(), String.t()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def maybe_update_password(%User{password_hash: "$2" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(%User{password_hash: "$6" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(%User{password_hash: "$pbkdf2" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(user, _), do: {:ok, user}
defp do_update_password(user, password) do
User.reset_password(user, %{password: password, password_confirmation: password})
end
end

View file

@ -2277,7 +2277,7 @@ defmodule Pleroma.User do
defp put_password_hash(
%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset
) do
change(changeset, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
change(changeset, password_hash: Pleroma.Password.hash_pwd_salt(password))
end
defp put_password_hash(changeset), do: changeset

View file

@ -6,7 +6,6 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
alias Pleroma.Registration
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.Plugs.AuthenticationPlug
import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
@ -15,8 +14,8 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
def get_user(%Plug.Conn{} = conn) do
with {:ok, {name, password}} <- fetch_credentials(conn),
{_, %User{} = user} <- {:user, fetch_user(name)},
{_, true} <- {:checkpw, AuthenticationPlug.checkpw(password, user.password_hash)},
{:ok, user} <- AuthenticationPlug.maybe_update_password(user, password) do
{_, true} <- {:checkpw, Pleroma.Password.checkpw(password, user.password_hash)},
{:ok, user} <- Pleroma.Password.maybe_update_password(user, password) do
{:ok, user}
else
{:error, _reason} = error -> error

View file

@ -6,7 +6,6 @@ defmodule Pleroma.Web.Auth.TOTPAuthenticator do
alias Pleroma.MFA
alias Pleroma.MFA.TOTP
alias Pleroma.User
alias Pleroma.Web.Plugs.AuthenticationPlug
@doc "Verify code or check backup code."
@spec verify(String.t(), User.t()) ::
@ -31,7 +30,7 @@ defmodule Pleroma.Web.Auth.TOTPAuthenticator do
code
)
when is_list(codes) and is_binary(code) do
hash_code = Enum.find(codes, fn hash -> AuthenticationPlug.checkpw(code, hash) end)
hash_code = Enum.find(codes, fn hash -> Pleroma.Password.checkpw(code, hash) end)
if hash_code do
MFA.invalidate_backup_code(user, hash_code)

View file

@ -17,7 +17,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.Plugs.AuthenticationPlug
alias Pleroma.Web.Utils.Params
require Logger
@ -356,7 +355,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
@spec confirm_current_password(User.t(), String.t()) :: {:ok, User.t()} | {:error, String.t()}
def confirm_current_password(user, password) do
with %User{local: true} = db_user <- User.get_cached_by_id(user.id),
true <- AuthenticationPlug.checkpw(password, db_user.password_hash) do
true <- Pleroma.Password.checkpw(password, db_user.password_hash) do
{:ok, db_user}
else
_ -> {:error, dgettext("errors", "Invalid password.")}

View file

@ -7,7 +7,6 @@ defmodule Pleroma.Web.MongooseIM.MongooseIMController do
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.Plugs.AuthenticationPlug
alias Pleroma.Web.Plugs.RateLimiter
plug(RateLimiter, [name: :authentication] when action in [:user_exists, :check_password])
@ -28,7 +27,7 @@ defmodule Pleroma.Web.MongooseIM.MongooseIMController do
def check_password(conn, %{"user" => username, "pass" => password}) do
with %User{password_hash: password_hash, is_active: true} <-
Repo.get_by(User, nickname: username, local: true),
true <- AuthenticationPlug.checkpw(password, password_hash) do
true <- Pleroma.Password.checkpw(password, password_hash) do
conn
|> json(true)
else

View file

@ -7,6 +7,7 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do
alias Pleroma.Helpers.AuthHelper
alias Pleroma.User
alias Pleroma.Password
import Plug.Conn
@ -25,8 +26,8 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do
} = conn,
_
) do
if checkpw(password, password_hash) do
{:ok, auth_user} = maybe_update_password(auth_user, password)
if Password.checkpw(password, password_hash) do
{:ok, auth_user} = Password.maybe_update_password(auth_user, password)
conn
|> assign(:user, auth_user)
@ -38,35 +39,6 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do
def call(conn, _), do: conn
def checkpw(password, "$6" <> _ = password_hash) do
:crypt.crypt(password, password_hash) == password_hash
end
def checkpw(password, "$2" <> _ = password_hash) do
# Handle bcrypt passwords for Mastodon migration
Bcrypt.verify_pass(password, password_hash)
end
def checkpw(password, "$pbkdf2" <> _ = password_hash) do
Pleroma.Password.Pbkdf2.verify_pass(password, password_hash)
end
def checkpw(_password, _password_hash) do
Logger.error("Password hash not recognized")
false
end
def maybe_update_password(%User{password_hash: "$2" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(%User{password_hash: "$6" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(user, _), do: {:ok, user}
defp do_update_password(user, password) do
User.reset_password(user, %{password: password, password_confirmation: password})
end
@spec checkpw(String.t(), String.t()) :: boolean
defdelegate checkpw(password, hash), to: Password
end

View file

@ -143,9 +143,7 @@ defmodule Pleroma.Mixfile do
{:sweet_xml, "~> 0.7.2"},
{:earmark, "~> 1.4.15"},
{:bbcode_pleroma, "~> 0.2.0"},
{:crypt,
git: "https://github.com/msantos/crypt.git",
ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"},
{:argon2_elixir, "~> 3.0.0"},
{:cors_plug, "~> 2.0"},
{:web_push_encryption, "~> 0.3.1"},
{:swoosh, "~> 1.0"},

View file

@ -1,4 +1,5 @@
%{
"argon2_elixir": {:hex, :argon2_elixir, "3.0.0", "fd4405f593e77b525a5c667282172dd32772d7c4fa58cdecdaae79d2713b6c5f", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "8b753b270af557d51ba13fcdebc0f0ab27a2a6792df72fd5a6cf9cfaffcedc57"},
"base62": {:hex, :base62, "1.2.2", "85c6627eb609317b70f555294045895ffaaeb1758666ab9ef9ca38865b11e629", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "d41336bda8eaa5be197f1e4592400513ee60518e5b9f4dcf38f4b4dae6f377bb"},
"bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.1", "5114d780459a04f2b4aeef52307de23de961b69e13a5cd98a911e39fda13f420", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "42182d5f46764def15bf9af83739e3bf4ad22661b1c34fc3e88558efced07279"},
@ -18,7 +19,6 @@
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"credo": {:git, "https://github.com/rrrene/credo.git", "1c1b99ea41a457761383d81aaf6a606913996fe7", [ref: "1c1b99ea41a457761383d81aaf6a606913996fe7"]},
"crypt": {:git, "https://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
"db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},

View file

@ -30,8 +30,8 @@ defmodule Pleroma.MFATest do
{:ok, [code1, code2]} = MFA.generate_backup_codes(user)
updated_user = refresh_record(user)
[hash1, hash2] = updated_user.multi_factor_authentication_settings.backup_codes
assert Pleroma.Password.Pbkdf2.verify_pass(code1, hash1)
assert Pleroma.Password.Pbkdf2.verify_pass(code2, hash2)
assert Pleroma.Password.checkpw(code1, hash1)
assert Pleroma.Password.checkpw(code2, hash2)
end
end

View file

@ -0,0 +1,65 @@
defmodule Pleroma.PasswordTest do
use Pleroma.DataCase, async: true
import Pleroma.Factory
import ExUnit.CaptureLog
alias Pleroma.Password
describe "hash_pwd_salt/1" do
test "returns a hash" do
assert "$argon2id" <> _ = Password.hash_pwd_salt("test")
end
end
describe "maybe_update_password/2" do
test "with a bcrypt hash, it updates to an argon2 hash" do
user = insert(:user, password_hash: Bcrypt.hash_pwd_salt("123"))
assert "$2" <> _ = user.password_hash
{:ok, user} = Password.maybe_update_password(user, "123")
assert "$argon2" <> _ = user.password_hash
end
test "with a pbkdf2 hash, it updates to an argon2 hash" do
user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("123"))
assert "$pbkdf2" <> _ = user.password_hash
{:ok, user} = Password.maybe_update_password(user, "123")
assert "$argon2" <> _ = user.password_hash
end
end
describe "checkpw/2" do
test "check pbkdf2 hash" do
hash =
"$pbkdf2-sha512$160000$loXqbp8GYls43F0i6lEfIw$AY.Ep.2pGe57j2hAPY635sI/6w7l9Q9u9Bp02PkPmF3OrClDtJAI8bCiivPr53OKMF7ph6iHhN68Rom5nEfC2A"
assert Password.checkpw("test-password", hash)
refute Password.checkpw("test-password1", hash)
end
test "check bcrypt hash" do
hash = "$2a$10$uyhC/R/zoE1ndwwCtMusK.TLVzkQ/Ugsbqp3uXI.CTTz0gBw.24jS"
assert Password.checkpw("password", hash)
refute Password.checkpw("password1", hash)
end
test "check argon2 hash" do
hash =
"$argon2id$v=19$m=65536,t=8,p=2$zEMMsTuK5KkL5AFWbX7jyQ$VyaQD7PF6e9btz0oH1YiAkWwIGZ7WNDZP8l+a/O171g"
assert Password.checkpw("password", hash)
refute Password.checkpw("password1", hash)
end
test "it returns false when hash invalid" do
hash =
"psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
assert capture_log(fn ->
refute Password.checkpw("password", hash)
end) =~ "[error] Password hash not recognized"
end
end
end

View file

@ -11,7 +11,7 @@ defmodule Pleroma.Web.Auth.BasicAuthTest do
conn: conn
} do
user = insert(:user)
assert Pleroma.Password.Pbkdf2.verify_pass("test", user.password_hash)
assert Pleroma.Password.checkpw("test", user.password_hash)
basic_auth_contents =
(URI.encode_www_form(user.nickname) <> ":" <> URI.encode_www_form("test"))

View file

@ -15,7 +15,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do
user =
insert(:user,
nickname: name,
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password)
password_hash: Pleroma.Password.hash_pwd_salt(password)
)
{:ok, [user: user, name: name, password: password]}
@ -30,7 +30,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do
assert {:ok, returned_user} = res
assert returned_user.id == user.id
assert "$pbkdf2" <> _ = returned_user.password_hash
assert "$argon2" <> _ = returned_user.password_hash
end
test "get_user/authorization with invalid password", %{name: name} do

View file

@ -34,7 +34,7 @@ defmodule Pleroma.Web.Auth.TOTPAuthenticatorTest do
hashed_codes =
backup_codes
|> Enum.map(&Pleroma.Password.Pbkdf2.hash_pwd_salt(&1))
|> Enum.map(&Pleroma.Password.hash_pwd_salt(&1))
user =
insert(:user,

View file

@ -41,13 +41,13 @@ defmodule Pleroma.Web.MongooseIMControllerTest do
end
test "/check_password", %{conn: conn} do
user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("cool"))
user = insert(:user, password_hash: Pleroma.Password.hash_pwd_salt("cool"))
_deactivated_user =
insert(:user,
nickname: "konata",
is_active: false,
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("cool")
password_hash: Pleroma.Password.hash_pwd_salt("cool")
)
res =

View file

@ -18,7 +18,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
@tag @skip
test "authorizes the existing user using LDAP credentials" do
password = "testpassword"
user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
user = insert(:user, password_hash: Pleroma.Password.hash_pwd_salt(password))
app = insert(:oauth_app, scopes: ["read", "write"])
host = Pleroma.Config.get([:ldap, :host]) |> to_charlist
@ -101,7 +101,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
@tag @skip
test "disallow authorization for wrong LDAP credentials" do
password = "testpassword"
user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
user = insert(:user, password_hash: Pleroma.Password.hash_pwd_salt(password))
app = insert(:oauth_app, scopes: ["read", "write"])
host = Pleroma.Config.get([:ldap, :host]) |> to_charlist

View file

@ -20,7 +20,7 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
backup_codes: [Pleroma.Password.Pbkdf2.hash_pwd_salt("test-code")],
backup_codes: [Pleroma.Password.hash_pwd_salt("test-code")],
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
@ -246,7 +246,7 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do
hashed_codes =
backup_codes
|> Enum.map(&Pleroma.Password.Pbkdf2.hash_pwd_salt(&1))
|> Enum.map(&Pleroma.Password.hash_pwd_salt(&1))
user =
insert(:user,

View file

@ -316,7 +316,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
app: app,
conn: conn
} do
user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("testpassword"))
user = insert(:user, password_hash: Pleroma.Password.hash_pwd_salt("testpassword"))
registration = insert(:registration, user: nil)
redirect_uri = OAuthController.default_redirect_uri(app)
@ -347,7 +347,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
app: app,
conn: conn
} do
user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("testpassword"))
user = insert(:user, password_hash: Pleroma.Password.hash_pwd_salt("testpassword"))
registration = insert(:registration, user: nil)
unlisted_redirect_uri = "http://cross-site-request.com"
@ -917,7 +917,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
password = "testpassword"
user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
user = insert(:user, password_hash: Pleroma.Password.hash_pwd_salt(password))
app = insert(:oauth_app, scopes: ["read", "write"])
@ -947,7 +947,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
user =
insert(:user,
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
password_hash: Pleroma.Password.hash_pwd_salt(password),
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
@ -1056,7 +1056,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
password = "testpassword"
{:ok, user} =
insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
insert(:user, password_hash: Pleroma.Password.hash_pwd_salt(password))
|> User.confirmation_changeset(set_confirmation: false)
|> User.update_and_set_cache()
@ -1084,7 +1084,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
user =
insert(:user,
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
password_hash: Pleroma.Password.hash_pwd_salt(password),
is_active: false
)
@ -1112,7 +1112,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
user =
insert(:user,
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
password_hash: Pleroma.Password.hash_pwd_salt(password),
password_reset_pending: true
)
@ -1141,7 +1141,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
user =
insert(:user,
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
password_hash: Pleroma.Password.hash_pwd_salt(password),
is_confirmed: false
)
@ -1169,7 +1169,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
user =
insert(:user,
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
password_hash: Pleroma.Password.hash_pwd_salt(password),
is_approved: false
)

View file

@ -17,7 +17,7 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
user = %User{
id: 1,
name: "dude",
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("guy")
password_hash: Pleroma.Password.hash_pwd_salt("guy")
}
conn =
@ -52,7 +52,7 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
end
test "with a bcrypt hash, it updates to a pkbdf2 hash", %{conn: conn} do
test "with a bcrypt hash, it updates to an argon2 hash", %{conn: conn} do
user = insert(:user, password_hash: Bcrypt.hash_pwd_salt("123"))
assert "$2" <> _ = user.password_hash
@ -67,21 +67,17 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
user = User.get_by_id(user.id)
assert "$pbkdf2" <> _ = user.password_hash
assert "$argon2" <> _ = user.password_hash
end
@tag :skip_on_mac
test "with a crypt hash, it updates to a pkbdf2 hash", %{conn: conn} do
user =
insert(:user,
password_hash:
"$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
)
test "with a pbkdf2 hash, it updates to an argon2 hash", %{conn: conn} do
user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("123"))
assert "$pbkdf2" <> _ = user.password_hash
conn =
conn
|> assign(:auth_user, user)
|> assign(:auth_credentials, %{password: "password"})
|> assign(:auth_credentials, %{password: "123"})
|> AuthenticationPlug.call(%{})
assert conn.assigns.user.id == conn.assigns.auth_user.id
@ -89,7 +85,7 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
user = User.get_by_id(user.id)
assert "$pbkdf2" <> _ = user.password_hash
assert "$argon2" <> _ = user.password_hash
end
describe "checkpw/2" do
@ -101,14 +97,6 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
refute AuthenticationPlug.checkpw("test-password1", hash)
end
@tag :skip_on_mac
test "check sha512-crypt hash" do
hash =
"$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
assert AuthenticationPlug.checkpw("password", hash)
end
test "check bcrypt hash" do
hash = "$2a$10$uyhC/R/zoE1ndwwCtMusK.TLVzkQ/Ugsbqp3uXI.CTTz0gBw.24jS"
@ -116,6 +104,14 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
refute AuthenticationPlug.checkpw("password1", hash)
end
test "check argon2 hash" do
hash =
"$argon2id$v=19$m=65536,t=8,p=2$zEMMsTuK5KkL5AFWbX7jyQ$VyaQD7PF6e9btz0oH1YiAkWwIGZ7WNDZP8l+a/O171g"
assert AuthenticationPlug.checkpw("password", hash)
refute AuthenticationPlug.checkpw("password1", hash)
end
test "it returns false when hash invalid" do
hash =
"psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"

View file

@ -96,7 +96,7 @@ defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do
assert response =~ "<h2>Password changed!</h2>"
user = refresh_record(user)
assert Pleroma.Password.Pbkdf2.verify_pass("test", user.password_hash)
assert Pleroma.Password.checkpw("test", user.password_hash)
assert Enum.empty?(Token.get_user_tokens(user))
end

View file

@ -553,7 +553,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
fetched_user = User.get_cached_by_id(user.id)
assert Pleroma.Password.Pbkdf2.verify_pass("newpass", fetched_user.password_hash) == true
assert Pleroma.Password.checkpw("newpass", fetched_user.password_hash) == true
end
end

View file

@ -7,7 +7,7 @@ defmodule Pleroma.Builders.UserBuilder do
email: "test@example.org",
name: "Test Name",
nickname: "testname",
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test"),
password_hash: Pleroma.Password.hash_pwd_salt("test"),
bio: "A tester.",
ap_id: "some id",
last_digest_emailed_at: NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),

View file

@ -47,12 +47,16 @@ defmodule Pleroma.Factory do
def user_factory(attrs \\ %{}) do
pem = Enum.random(@rsa_keys)
# Argon2.hash_pwd_salt("test")
# it really eats CPU time, so we use a precomputed hash
password_hash =
"$argon2id$v=19$m=65536,t=8,p=2$FEAarFuiOsROO24NHIHMYw$oxdaz2fTPpuU+dYCl60FsqE65T1Tjy6lGikKfmql4xo"
user = %User{
name: sequence(:name, &"Test テスト User #{&1}"),
email: sequence(:email, &"user#{&1}@example.com"),
nickname: sequence(:nickname, &"nick#{&1}"),
password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test"),
password_hash: password_hash,
bio: sequence(:bio, &"Tester Number #{&1}"),
is_discoverable: true,
last_digest_emailed_at: NaiveDateTime.utc_now(),