Scoty

Scoty

Hey, guys,

I am trying to write a simple module that prepares a valid URL link. The URL needs a checksum param passed. The checksum calculations is very simple: concat all the values of the passed params(key + value) add salt and hash it.

Here is the sample* code(lets ignore for the moment that I need some kind of ordered map, cause there is no guarantee that the map is iterated in the same order. ScRequest is a struct containing the secret_key and the hashish algorithm):

defp calculate_v4_checksum(sc_request, params) do
  # this fails: str_to_hash = Enum.map(params, fn {k, v} -> Atom.to_string(k) <> v end) <> sc_request.secret_key
  str_to_hash = Enum.map(params, fn {k, v} -> Atom.to_string(k) <> v end)
  IO.puts (str_to_hash)
  IO.puts (sc_request.secret_key)
  # this fails: IO.puts (str_to_hash <> sc_request.secret_key)
  # or this: :crypto.hash(sc_request.algorithm, str_to_hash <> sc_request.secret_key)
  :crypto.hash(sc_request.algorithm, str_to_hash)
  |> Base.encode16(case: :lower)
end

Why the concatenation of the salt(secret_key) fails with ArgumentError ? Currently I can only hash the concatenated params…

Showing Posts 1 to 4

NobbZ

NobbZ

Of course it does. All (well, most) Enum functions return a list. You can not use <> on Lists.

If I understand you correctly, you want this:

str_to_hash = params
|> Enum.map({k, v} -> "#{k}#{v}" end)
|> Enum.concat([sc_request.secret_key])
|> Enum.join

(untested)

Scoty

Scoty OP

Thank you, NobbZ, that is exactly what I wanted.

Added just the fn keyword and the function now looks like this:

  defp calculate_v4_checksum(sc_request, params) do
	str_to_hash = params
				  |> Enum.map(fn {k, v} -> "#{k}#{v}" end)
				  |> Enum.concat([sc_request.secret_key])
				  |> Enum.join
	:crypto.hash(sc_request.algorithm, str_to_hash)
	|> Base.encode16(case: :lower)
  end

But back to my original question: why this fails(aren’t both values strings ?):

IO.puts (str_to_hash <> sc_request.secret_key)
NobbZ

NobbZ

PS: You can simulate your ordered map roughly like this (and also do it single pipe):

params
|> Enum.sort()
|> Enum.map(fn {k, v} -> "#{k}#{v}" end)
|> Enum.concat([sc_request.secret_key])
|> Enum.join
|> (&:crypto.hash(sc_request.algorithm, &1)).()
|> Base.encode16(case: :lower)
NobbZ

NobbZ

As I already said in my first answer, Enum.map returns a list, due to the function you passed into it, that was a list of String.t, but a list of strings is not a string. <> does really only work for binaries (and therefore for strings as well).

— All posts loaded —

Where Next? Top

Trending in Chat/Questions Top

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews