diff options
author | href <href@random.sh> | 2020-07-07 21:39:10 +0200 |
---|---|---|
committer | href <href@random.sh> | 2020-07-07 21:39:51 +0200 |
commit | d6ee134a5957e299c3ad59011df320b3c41e6e61 (patch) | |
tree | 29567e6635466f8a3415a935b3cc8a777019f5bc /lib/lsg_irc/sms_plugin.ex | |
parent | bleh (diff) |
pouet
Diffstat (limited to 'lib/lsg_irc/sms_plugin.ex')
-rw-r--r-- | lib/lsg_irc/sms_plugin.ex | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/lib/lsg_irc/sms_plugin.ex b/lib/lsg_irc/sms_plugin.ex new file mode 100644 index 0000000..60554fb --- /dev/null +++ b/lib/lsg_irc/sms_plugin.ex @@ -0,0 +1,163 @@ +defmodule LSG.IRC.SmsPlugin do + @moduledoc """ + ## sms + + * **!sms `<nick>` `<message>`** envoie un SMS. + """ + def short_irc_doc, do: false + def irc_doc, do: @moduledoc + require Logger + + def incoming(from, "enable "<>key) do + key = String.trim(key) + account = IRC.Account.find_meta_account("sms-validation-code", String.downcase(key)) + if account do + net = IRC.Account.get_meta(account, "sms-validation-target") + IRC.Account.put_meta(account, "sms-number", from) + IRC.Account.delete_meta(account, "sms-validation-code") + IRC.Account.delete_meta(account, "sms-validation-number") + IRC.Account.delete_meta(account, "sms-validation-target") + IRC.Connection.broadcast_message(net, account, "SMS Number #{from} added!") + send_sms(from, "Yay! Number linked to account #{account.name}") + end + end + + def incoming(from, message) do + account = IRC.Account.find_meta_account("sms-number", from) + if account do + reply_fun = fn(text) -> + send_sms(from, text) + end + trigger_text = if Enum.any?(IRC.Connection.triggers(), fn({trigger, _}) -> String.starts_with?(message, trigger) end) do + message + else + "!"<>message + end + message = %IRC.Message{ + transport: :sms, + network: "sms", + channel: nil, + text: message, + account: account, + sender: %ExIRC.SenderInfo{nick: account.name}, + replyfun: reply_fun, + trigger: IRC.Connection.extract_trigger(trigger_text) + } + IO.puts("converted sms to message: #{inspect message}") + IRC.Connection.publish(message, ["message:sms"]) + message + end + end + + def my_number() do + Keyword.get(Application.get_env(:lsg, :sms, []), :number, "+33000000000") + end + + def start_link() do + GenServer.start_link(__MODULE__, []) + end + + def path() do + account = Keyword.get(Application.get_env(:lsg, :sms), :account) + "https://eu.api.ovh.com/1.0/sms/#{account}" + end + + def path(rest) do + Path.join(path(), rest) + end + + def send_sms(number, text) do + url = path("/virtualNumbers/#{my_number()}/jobs") + body = %{ + "message" => text, + "receivers" => [number], + #"senderForResponse" => true, + #"noStopClause" => true, + "charset" => "UTF-8", + "coding" => "8bit" + } |> Poison.encode!() + headers = [{"content-type", "application/json"}] ++ sign("POST", url, body) + options = [] + case HTTPoison.post(url, body, headers, options) do + {:ok, %HTTPoison.Response{status_code: 200}} -> :ok + {:ok, %HTTPoison.Response{status_code: code} = resp} -> + Logger.error("SMS Error: #{inspect resp}") + {:error, code} + {:error, error} -> {:error, error} + end + end + + def init([]) do + {:ok, _} = Registry.register(IRC.PubSub, "trigger:sms", []) + :ok = register_ovh_callback() + {:ok, %{}} + end + + def handle_info({:irc, :trigger, "sms", m = %IRC.Message{trigger: %IRC.Trigger{type: :bang, args: [nick | text]}}}, state) do + with \ + {:tree, false} <- {:tree, m.sender.nick == "Tree"}, + {_, %IRC.Account{} = account} <- {:account, IRC.Account.find_always_by_nick(m.network, m.channel, nick)}, + {_, number} when not is_nil(number) <- {:number, IRC.Account.get_meta(account, "sms-number")} + do + text = Enum.join(text, " ") + sender = if m.channel do + "#{m.channel} <#{m.sender.nick}> " + else + "<#{m.sender.nick}> " + end + case send_sms(number, sender<>text) do + :ok -> m.replyfun.("sent!") + {:error, error} -> m.replyfun.("not sent, error: #{inspect error}") + end + else + {:tree, _} -> m.replyfun.("Tree: va en enfer") + {:account, _} -> m.replyfun.("#{nick} not known") + {:number, _} -> m.replyfun.("#{nick} have not enabled sms") + end + {:noreply, state} + end + + def handle_info(msg, state) do + {:noreply, state} + end + + defp register_ovh_callback() do + url = path() + body = %{ + "callBack" =>LSGWeb.Router.Helpers.sms_url(LSGWeb.Endpoint, :ovh_callback), + "smsResponse" => %{ + "cgiUrl" => LSGWeb.Router.Helpers.sms_url(LSGWeb.Endpoint, :ovh_callback), + "responseType" => "cgi" + } + } |> Poison.encode!() + headers = [{"content-type", "application/json"}] ++ sign("PUT", url, body) + options = [] + case HTTPoison.put(url, body, headers, options) do + {:ok, %HTTPoison.Response{status_code: 200}} -> + :ok + error -> error + end + end + + defp sign(method, url, body) do + ts = DateTime.utc_now() |> DateTime.to_unix() + as = env(:app_secret) + ck = env(:consumer_key) + sign = Enum.join([as, ck, String.upcase(method), url, body, ts], "+") + sign_hex = :crypto.hash(:sha, sign) |> Base.encode16(case: :lower) + headers = [{"X-OVH-Application", env(:app_key)}, {"X-OVH-Timestamp", ts}, + {"X-OVH-Signature", "$1$"<>sign_hex}, {"X-Ovh-Consumer", ck}] + end + + def parse_number(num) do + {:error, :todo} + end + + defp env() do + Application.get_env(:lsg, :sms) + end + + defp env(key) do + Keyword.get(env(), key) + end +end |