defmodule FileSniffer do @signatures [ {<<0x7F, 0x45, 0x4C, 0x46>>, "application/octet-stream"}, {<<0x42, 0x4D>>, "image/bmp"}, {<<0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A>>, "image/png"}, {<<0xFF, 0xD8, 0xFF>>, "image/jpg"}, {<<0x47, 0x49, 0x46>>, "image/gif"} ] @file_types %{ "exe" => "application/octet-stream", "bmp" => "image/bmp", "png" => "image/png", "jpg" => "image/jpg", "gif" => "image/gif" } def type_from_extension(extension), do: @file_types[extension] def type_from_binary(file_binary) do Enum.find_value(@signatures, fn {signature, type} -> with signature_size <- byte_size(signature), <> <- file_binary, true <- file_signature == signature do type else _ -> nil end end) end def verify(file_binary, extension) do ext_type = type_from_extension(extension) bin_type = type_from_binary(file_binary) case ext_type == bin_type do true when ext_type != nil and bin_type != nil -> {:ok, ext_type} _ -> {:error, "Warning, file format and file extension do not match."} end end end