在test

时间:2017-03-20 03:06:57

标签: elixir

我尝试使用Fernet.Ecto.String.dump以这种方式加密String ...

defp encrypt_password(changeset) do
  case changeset do
    %Ecto.Changeset{valid?: true, changes: %{password: password}} ->
      put_change(changeset, :password_hash, Fernet.Ecto.String.dump(password))
    _ ->
      changeset
  end
end

...在此自动生成的测试中(mix phoenix.gen.json User users...)...

@valid_attrs %{email: "email@domain.tld", password: "q1w2e3"}

test "creates and renders resource when data is valid", %{conn: conn} do
  conn = post conn, user_path(conn, :create), user: @valid_attrs
  body = json_response(conn, 201)
  |> IO.inspect
  assert body["data"]["id"]
  assert body["data"]["email"]
  assert body["data"]["password"]
  assert body["data"]["password_hash"]
  assert Repo.get_by(User, email: "email@domain.tld")
end

......得到了这个:

1) test creates and renders resource when data is valid (Api.UserControllerTest)
 test/controllers/user_controller_test.exs:32
 ** (ArgumentError) argument error
 stacktrace:
   :erlang.byte_size({:ok, "gAAAAABYzq2ofkNpJauc1vIDNrze1ORAMJXW0j0WN5bDong-cpgYYfaV75RYbX3A5yPl4fo86ctkZfszI8ePXGMejW50eRnfeg=="})
   (fernetex) lib/fernetex.ex:193: Fernet.pad/1
   (fernetex) lib/fernetex.ex:176: Fernet.encrypt/3
   (fernetex) lib/fernetex.ex:154: Fernet.generate/4
   (fernet_ecto) lib/fernet_ecto/type.ex:9: Fernet.Ecto.Type.encrypt/2
   (ecto) lib/ecto/type.ex:662: Ecto.Type.process_dumpers/3
   (ecto) lib/ecto/repo/schema.ex:695: Ecto.Repo.Schema.dump_field!/6
   (ecto) lib/ecto/repo/schema.ex:708: anonymous fn/6 in Ecto.Repo.Schema.dump_fields!/5
   (stdlib) lists.erl:1263: :lists.foldl/3
   (ecto) lib/ecto/repo/schema.ex:706: Ecto.Repo.Schema.dump_fields!/5
   (ecto) lib/ecto/repo/schema.ex:655: Ecto.Repo.Schema.dump_changes!/6
   (ecto) lib/ecto/repo/schema.ex:200: anonymous fn/13 in Ecto.Repo.Schema.do_insert/4
   (api) web/controllers/user_controller.ex:16: Api.UserController.create/2
   (api) web/controllers/user_controller.ex:1: Api.UserController.action/2
   (api) web/controllers/user_controller.ex:1: Api.UserController.phoenix_controller_pipeline/2
   (api) lib/api/endpoint.ex:1: Api.Endpoint.instrument/4
   (api) lib/phoenix/router.ex:261: Api.Router.dispatch/2
   (api) web/router.ex:1: Api.Router.do_call/2
   (api) lib/api/endpoint.ex:1: Api.Endpoint.phoenix_pipeline/1
   (api) lib/api/endpoint.ex:1: Api.Endpoint.call/2

当我在iex -S mix phoenix.server中使用该命令时,它可以正常工作:

iex(15)> Fernet.Ecto.String.dump("teste")
{:ok, "gAAAAABYzq-iDjQb5i1MYY8RXbFl9ZFfDQp2wyVWqAdPJIVKgMtFap-P8AtuvsNXqrcedp5CGaJjS9M2kBD60OPOR4l_tkDO8w=="}
iex(16)>

如果我使用put_change(changeset, :password_hash, password)避免加密,则测试将通过。

这是DB中的结构:

schema "users" do
  field :name, :string
  field :email, :string
  field :password, :string, virtual: true
  field :password_hash, Fernet.Ecto.String

根据documentationFernet.Ecto.String存储在数据库的:binary列中:

add :password_hash, :binary

任何人都可以帮我弄清楚为什么这个测试失败了吗?

其他(不那么重要/相关)信息:

1 个答案:

答案 0 :(得分:2)

我认为这是因为Fernet.Ecto.String.dump(password)返回{:ok, "hash-goes-here"}的元组,并且您正在尝试将此元组分配给字符串字段。

你应该试试这个:

defp encrypt_password(changeset) do
  case changeset do
    %Ecto.Changeset{valid?: true, changes: %{password: password}} ->
      {:ok, hash} = Fernet.Ecto.String.dump(password)
      put_change(changeset, :password_hash, hash)
    _ ->
      changeset
  end
end

这样,它只会将哈希值分配给字段。