X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fpassword.ex;h=92d78552bc7c6ed3ede71014c3f1f663ba2cb476;hb=cc63a89b5d81f11f3c0dc1cc4130ac6f20cbe260;hp=e96249650b9177e366fe781393ae78a3f4a12b3c;hpb=c7cd9bd5911f8393fa758e329f8786913a5c321f;p=akkoma diff --git a/lib/pleroma/password.ex b/lib/pleroma/password.ex index e96249650..92d78552b 100644 --- a/lib/pleroma/password.ex +++ b/lib/pleroma/password.ex @@ -1,55 +1,55 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - defmodule Pleroma.Password do @moduledoc """ - This module implements Pleroma.Password passwords in terms of Plug.Crypto. + 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 Plug.Crypto.KeyGenerator - - def decode64(str) do - str - |> String.replace(".", "+") - |> Base.decode64!(padding: false) - end - - def encode64(bin) do - bin - |> Base.encode64(padding: false) - |> String.replace("+", ".") - end + alias Pleroma.User + alias Pleroma.Password.Pbkdf2 + require Logger - def verify_pass(password, hash) do - ["pbkdf2-" <> digest, iterations, salt, hash] = String.split(hash, "$", trim: true) + @hashing_module Argon2 - salt = decode64(salt) + @spec hash_pwd_salt(String.t()) :: String.t() + defdelegate hash_pwd_salt(pass), to: @hashing_module - iterations = String.to_integer(iterations) + @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 - digest = String.to_atom(digest) + def checkpw(password, "$pbkdf2" <> _ = password_hash) do + Pbkdf2.verify_pass(password, password_hash) + end - binary_hash = - KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64) + def checkpw(password, "$argon2" <> _ = password_hash) do + Argon2.verify_pass(password, password_hash) + end - encode64(binary_hash) == hash + def checkpw(_password, _password_hash) do + Logger.error("Password hash not recognized") + false end - def hash_pwd_salt(password, opts \\ []) do - salt = - Keyword.get_lazy(opts, :salt, fn -> - :crypto.strong_rand_bytes(16) - 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 - digest = Keyword.get(opts, :digest, :sha512) + def maybe_update_password(%User{password_hash: "$6" <> _} = user, password) do + do_update_password(user, password) + end - iterations = - Keyword.get(opts, :iterations, Pleroma.Config.get([:password, :iterations], 160_000)) + def maybe_update_password(%User{password_hash: "$pbkdf2" <> _} = user, password) do + do_update_password(user, password) + end - binary_hash = - KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64) + def maybe_update_password(user, _), do: {:ok, user} - "$pbkdf2-#{digest}$#{iterations}$#{encode64(salt)}$#{encode64(binary_hash)}" + defp do_update_password(user, password) do + User.reset_password(user, %{password: password, password_confirmation: password}) end end