summaryrefslogtreecommitdiff
path: root/lib/lsg_irc/sms_plugin.ex
diff options
context:
space:
mode:
authorhref <href@random.sh>2020-07-07 21:39:10 +0200
committerhref <href@random.sh>2020-07-07 21:39:51 +0200
commitd6ee134a5957e299c3ad59011df320b3c41e6e61 (patch)
tree29567e6635466f8a3415a935b3cc8a777019f5bc /lib/lsg_irc/sms_plugin.ex
parentbleh (diff)
pouet
Diffstat (limited to 'lib/lsg_irc/sms_plugin.ex')
-rw-r--r--lib/lsg_irc/sms_plugin.ex163
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