Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Unsafe atom operation #15

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion lib/mimemail.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
defmodule MimeMail do
@on_load :preload_atoms
@atoms_to_preload [:'content-transfer-encoding', :'content-type', :'content-disposition', :'content-id', :'delivered-to']

@type header :: {:raw,binary} | MimeMail.Header.t #ever the raw line or any term implementing MimeMail.Header.to_ascii
@type body :: binary | [MimeMail.t] | {:raw,binary} #ever the raw body or list of mail for multipart or binary for decoded content
@type t :: %MimeMail{headers: [{key::binary,header}], body: body}
Expand All @@ -10,6 +13,8 @@ defmodule MimeMail do
defdelegate get(dict,k,v), to: Map
defdelegate pop(dict,k), to: Map

def preload_atoms, do: @atoms_to_preload |> Enum.each(&is_atom/1)

def from_string(data) do
[headers, body] = case String.split(data, "\r\n\r\n", parts: 2) do
two_parts = [_, _] -> two_parts
Expand All @@ -19,7 +24,14 @@ defmodule MimeMail do
|> String.replace(~r/\r\n([^\t ])/,"\r\n!\\1")
|> String.split("\r\n!")
|> Enum.map(&{String.split(&1,~r/\s*:/,parts: 2),&1})
headers=for {[k,_],v}<-headers, do: {:"#{String.downcase(k)}", {:raw,v}}
headers = for {[k,_],v}<-headers do
k = k |> String.downcase
try do
{k |> String.to_existing_atom, {:raw,v}}
rescue
ArgumentError -> {k, {:raw,v}}
end
end
%MimeMail{headers: headers, body: {:raw,body}}
end

Expand Down
10 changes: 5 additions & 5 deletions lib/mimemail_headers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ defmodule MimeMail.Emails do
parsed=for {k,{:raw,v}}<-headers, k in [:from,:to,:cc,:cci,:'delivered-to'] do
{k,v|>MimeMail.header_value|>parse_header}
end
%{mail| headers: Enum.reduce(parsed,headers, fn {k,v},acc-> Dict.put(acc,k,v) end)}
%{mail| headers: Enum.reduce(parsed,headers, fn {k,v},acc-> List.keystore(acc,k,0,{k,v}) end)}
end
defimpl MimeMail.Header, for: List do # a list header is a mailbox spec list
def to_ascii(mail_list) do # a mail is a struct %{name: nil, address: ""}
Expand All @@ -40,9 +40,9 @@ defmodule MimeMail.Params do
def parse_kv(<<c,rest::binary>>,:key,keyacc,acc) when c in [?\s,?\t,?\r,?\n,?;], do:
parse_kv(rest,:key,keyacc,acc) # not allowed characters in key, skip
def parse_kv(<<?=,?",rest::binary>>,:key,keyacc,acc), do:
parse_kv(rest,:quotedvalue,[],[{:"#{keyacc|>Enum.reverse|>to_string|>String.downcase}",""}|acc]) # enter in a quoted value, save key in res acc
parse_kv(rest,:quotedvalue,[],[{keyacc|>Enum.reverse|>to_string|>String.downcase|>String.to_existing_atom,""}|acc]) # enter in a quoted value, save key in res acc
def parse_kv(<<?=,rest::binary>>,:key,keyacc,acc), do:
parse_kv(rest,:value,[],[{:"#{keyacc|>Enum.reverse|>to_string|>String.downcase}",""}|acc]) # enter in a simple value, save key in res acc
parse_kv(rest,:value,[],[{keyacc|>Enum.reverse|>to_string|>String.downcase|>String.to_existing_atom,""}|acc]) # enter in a simple value, save key in res acc
def parse_kv(<<c,rest::binary>>,:key,keyacc,acc), do:
parse_kv(rest,:key,[c|keyacc],acc) # allowed char in key, add to key acc
def parse_kv(<<?\\,?",rest::binary>>,:quotedvalue,valueacc,acc), do:
Expand Down Expand Up @@ -71,7 +71,7 @@ defmodule MimeMail.CTParams do
end
def decode_headers(%MimeMail{headers: headers}=mail) do
parsed_mail_headers=for {k,{:raw,v}}<-headers,match?("content-"<>_,"#{k}"), do: {k,v|>MimeMail.header_value|>parse_header}
%{mail| headers: Enum.reduce(parsed_mail_headers,headers, fn {k,v},acc-> Dict.put(acc,k,v) end)}
%{mail| headers: Enum.reduce(parsed_mail_headers,headers, fn {k,v},acc-> List.keystore(acc,k,0,{k,v}) end)}
end

defimpl MimeMail.Header, for: Tuple do # a 2 tuple header is "value; key1=value1; key2=value2"
Expand Down Expand Up @@ -129,7 +129,7 @@ defmodule MimeMail.Words do

def decode_headers(%MimeMail{headers: headers}=mail) do
parsed_mail_headers=for {k,{:raw,v}}<-headers, k in [:subject], do: {k,v|>MimeMail.header_value|>word_decode}
%{mail| headers: Enum.reduce(parsed_mail_headers,headers, fn {k,v},acc-> Dict.put(acc,k,v) end)}
%{mail| headers: Enum.reduce(parsed_mail_headers,headers, fn {k,v},acc-> List.keystore(acc,k,0,{k,v}) end)}
end

defimpl MimeMail.Header, for: BitString do # a 2 tuple header is "value; key1=value1; key2=value2"
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ defmodule Mailibex.Mixfile do

def project do
[app: :mailibex,
version: "0.1.1",
version: "0.2.0",
elixir: "~> 1.0",
description: description,
package: package,
Expand Down