summaryrefslogtreecommitdiff
path: root/lib/lsg
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
parentbleh (diff)
pouet
Diffstat (limited to 'lib/lsg')
-rw-r--r--lib/lsg/application.ex7
-rw-r--r--lib/lsg/auth_token.ex59
-rw-r--r--lib/lsg/telegram.ex254
3 files changed, 319 insertions, 1 deletions
diff --git a/lib/lsg/application.ex b/lib/lsg/application.ex
index 972767f..a12253b 100644
--- a/lib/lsg/application.ex
+++ b/lib/lsg/application.ex
@@ -15,13 +15,18 @@ defmodule LSG.Application do
worker(Registry, [[keys: :duplicate, name: LSG.BroadcastRegistry]], id: :registry_broadcast),
worker(LSG.IcecastAgent, []),
worker(LSG.Token, []),
+ worker(LSG.AuthToken, []),
+ {GenMagic.Pool, [name: LSG.GenMagic, pool_size: 2]},
+ LSG.Telegram,
#worker(LSG.Icecast, []),
] ++ LSG.IRC.application_childs
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: LSG.Supervisor]
- Supervisor.start_link(children, opts)
+ sup = Supervisor.start_link(children, opts)
+ LSG.IRC.after_start()
+ sup
end
# Tell Phoenix to update the endpoint configuration
diff --git a/lib/lsg/auth_token.ex b/lib/lsg/auth_token.ex
new file mode 100644
index 0000000..0c5ba58
--- /dev/null
+++ b/lib/lsg/auth_token.ex
@@ -0,0 +1,59 @@
+defmodule LSG.AuthToken do
+ use GenServer
+
+ def start_link() do
+ GenServer.start_link(__MODULE__, [], [name: __MODULE__])
+ end
+
+ def lookup(id) do
+ GenServer.call(__MODULE__, {:lookup, id})
+ end
+
+ def new_path(account, perks \\ nil) do
+ case new(account, perks) do
+ {:ok, id} ->
+ LSGWeb.Router.Helpers.login_path(LSGWeb.Endpoint, :token, id)
+ error ->
+ error
+ end
+ end
+
+ def new_url(account, perks \\ nil) do
+ case new(account, perks) do
+ {:ok, id} ->
+ LSGWeb.Router.Helpers.login_url(LSGWeb.Endpoint, :token, id)
+ error ->
+ error
+ end
+ end
+
+ def new(account, perks \\ nil) do
+ GenServer.call(__MODULE__, {:new, account, perks})
+ end
+
+ def init(_) do
+ {:ok, Map.new}
+ end
+
+ def handle_call({:lookup, id}, _, state) do
+ IO.inspect(state)
+ with \
+ {account, date, perks} <- Map.get(state, id),
+ d when d > 0 <- DateTime.diff(date, DateTime.utc_now())
+ do
+ {:reply, {:ok, account, perks}, Map.delete(state, id)}
+ else
+ x ->
+ IO.inspect(x)
+ {:reply, {:error, :invalid_token}, state}
+ end
+ end
+
+ def handle_call({:new, account, perks}, _, state) do
+ id = IRC.UserTrack.Id.token()
+ expire = DateTime.utc_now()
+ |> DateTime.add(15*60, :second)
+ {:reply, {:ok, id}, Map.put(state, id, {account, expire, perks})}
+ end
+
+end
diff --git a/lib/lsg/telegram.ex b/lib/lsg/telegram.ex
new file mode 100644
index 0000000..7541b13
--- /dev/null
+++ b/lib/lsg/telegram.ex
@@ -0,0 +1,254 @@
+defmodule LSG.Telegram do
+ require Logger
+
+ use Telegram.Bot,
+ token: Keyword.get(Application.get_env(:lsg, :telegram, []), :key),
+ username: Keyword.get(Application.get_env(:lsg, :telegram), :nick, "beauttebot"),
+ purge: true
+
+ def my_path() do
+ "https://t.me/beauttebot"
+ end
+
+ def init() do
+ # Create users in track: IRC.UserTrack.connected(...)
+ :ok
+ end
+
+ def handle_update(_, %{"message" => m = %{"chat" => %{"type" => "private"}, "text" => text = "/start"<>_}}) do
+ text = "Hello to beautte! Query the bot on IRC and say \"enable-telegram\" to continue."
+ send_message(m["chat"]["id"], text)
+ end
+
+ def handle_update(_, %{"message" => m = %{"chat" => %{"type" => "private"}, "text" => text = "/enable"<>_}}) do
+ key = case String.split(text, " ") do
+ ["/enable", key | _] -> key
+ _ -> "nil"
+ end
+
+ #Handled message "1247435154:AAGnSSCnySn0RuVxy_SUcDEoOX_rbF6vdq0" %{"message" =>
+ # %{"chat" => %{"first_name" => "J", "id" => 2075406, "type" => "private", "username" => "ahref"},
+ # "date" => 1591027272, "entities" =>
+ # [%{"length" => 7, "offset" => 0, "type" => "bot_command"}],
+ # "from" => %{"first_name" => "J", "id" => 2075406, "is_bot" => false, "language_code" => "en", "username" => "ahref"},
+ # "message_id" => 11, "text" => "/enable salope"}, "update_id" => 764148578}
+ account = IRC.Account.find_meta_account("telegram-validation-code", String.downcase(key))
+ text = if account do
+ net = IRC.Account.get_meta(account, "telegram-validation-target")
+ IRC.Account.put_meta(account, "telegram-id", m["chat"]["id"])
+ IRC.Account.put_meta(account, "telegram-username", m["chat"]["username"])
+ IRC.Account.delete_meta(account, "telegram-validation-code")
+ IRC.Account.delete_meta(account, "telegram-validation-target")
+ IRC.Connection.broadcast_message(net, account, "Telegram #{m["chat"]["username"]} account added!")
+ "Yay! Linked to account #{account.name}"
+ else
+ "Token invalid"
+ end
+ send_message(m["chat"]["id"], text)
+ end
+
+ #[debug] Unhandled update: %{"message" =>
+ # %{"chat" => %{"first_name" => "J", "id" => 2075406, "type" => "private", "username" => "ahref"},
+ # "date" => 1591096015,
+ # "from" => %{"first_name" => "J", "id" => 2075406, "is_bot" => false, "language_code" => "en", "username" => "ahref"},
+ # "message_id" => 29,
+ # "photo" => [
+ # %{"file_id" => "AgACAgQAAxkBAAMdXtYyz4RQqLcpOlR6xKK3w3NayHAAAnCzMRuL4bFSgl_cTXMl4m5G_T0kXQADAQADAgADbQADZVMBAAEaBA",
+ # "file_size" => 9544, "file_unique_id" => "AQADRv09JF0AA2VTAQAB", "height" => 95, "width" => 320},
+ # %{"file_id" => "AgACAgQAAxkBAAMdXtYyz4RQqLcpOlR6xKK3w3NayHAAAnCzMRuL4bFSgl_cTXMl4m5G_T0kXQADAQADAgADeAADZFMBAAEaBA",
+ # "file_size" => 21420, "file_unique_id" => "AQADRv09JF0AA2RTAQAB", "height" => 148, "width" => 501}]},
+ # "update_id" => 218161546}
+
+ def handle_update(token, data = %{"message" => %{"photo" => _}}) do
+ start_upload(token, "photo", data)
+ end
+
+ def handle_update(token, data = %{"message" => %{"voice" => _}}) do
+ start_upload(token, "voice", data)
+ end
+
+ def handle_update(token, data = %{"message" => %{"video" => _}}) do
+ start_upload(token, "video", data)
+ end
+
+ def handle_update(token, data = %{"message" => %{"document" => _}}) do
+ start_upload(token, "document", data)
+ end
+
+ def handle_update(token, data = %{"message" => %{"animation" => _}}) do
+ start_upload(token, "animation", data)
+ end
+
+ def start_upload(token, _, %{"message" => m = %{"chat" => %{"id" => id, "type" => "private"}}}) do
+ account = IRC.Account.find_meta_account("telegram-id", id)
+ if account do
+ text = if(m["text"], do: m["text"], else: nil)
+ targets = IRC.Membership.of_account(account)
+ |> Enum.map(fn({net, chan}) -> "#{net}/#{chan}" end)
+ |> Enum.map(fn(i) -> %{"text" => i, "callback_data" => i} end)
+ kb = if Enum.count(targets) > 1 do
+ [%{"text" => "everywhere", "callback_data" => "everywhere"}] ++ targets
+ else
+ targets
+ end
+ |> Enum.chunk_every(2)
+ keyboard = %{"inline_keyboard" => kb}
+ Telegram.Api.request(token, "sendMessage", chat_id: id, text: "Where should I send this file?", reply_markup: keyboard, reply_to_message_id: m["message_id"])
+ end
+ end
+
+ #[debug] Unhandled update: %{"callback_query" =>
+ # %{
+ # "chat_instance" => "-7948978714441865930", "data" => "evolu.net/#dmz",
+ # "from" => %{"first_name" => "J", "id" => 2075406, "is_bot" => false, "language_code" => "en", "username" => "ahref"},
+ # "id" => "8913804780149600",
+ # "message" => %{"chat" => %{"first_name" => "J", "id" => 2075406, "type" => "private", "username" => "ahref"},
+ # "date" => 1591098553, "from" => %{"first_name" => "devbeautte", "id" => 1293058838, "is_bot" => true, "username" => "devbeauttebot"},
+ # "message_id" => 62,
+ # "reply_markup" => %{"inline_keyboard" => [[%{"callback_data" => "random/#", "text" => "random/#"},
+ # %{"callback_data" => "evolu.net/#dmz", "text" => "evolu.net/#dmz"}]]},
+ # "text" => "Where should I send the file?"}
+ # }
+ # , "update_id" => 218161568}
+
+ def handle_update(t, %{"callback_query" => cb = %{"data" => "resend", "id" => id, "message" => m = %{"message_id" => m_id, "chat" => %{"id" => chat_id}, "reply_to_message" => op}}}) do
+ end
+
+ def handle_update(t, %{"callback_query" => cb = %{"data" => target, "id" => id, "message" => m = %{"message_id" => m_id, "chat" => %{"id" => chat_id}, "reply_to_message" => op}}}) do
+ account = IRC.Account.find_meta_account("telegram-id", chat_id)
+ if account do
+ target = case String.split(target, "/") do
+ ["everywhere"] -> IRC.Membership.of_account(account)
+ [net, chan] -> [{net, chan}]
+ end
+ Telegram.Api.request(t, "editMessageText", chat_id: chat_id, message_id: m_id, text: "Processing...", reply_markup: %{})
+
+ {content, type} = cond do
+ op["photo"] -> {op["photo"], ""}
+ op["voice"] -> {op["voice"], " a voice message"}
+ op["video"] -> {op["video"], ""}
+ op["document"] -> {op["document"], ""}
+ op["animation"] -> {op["animation"], ""}
+ end
+
+ file = if is_list(content) && Enum.count(content) > 1 do
+ Enum.sort_by(content, fn(p) -> p["file_size"] end, &>=/2)
+ |> List.first()
+ else
+ content
+ end
+ file_id = file["file_id"]
+ file_unique_id = file["file_unique_id"]
+ text = if(op["caption"], do: ": "<> op["caption"] <> "", else: "")
+ resend = %{"inline_keyboard" => [ [%{"text" => "re-share", "callback_data" => "resend"}] ]}
+ spawn(fn() ->
+ with \
+ {:ok, file} <- Telegram.Api.request(t, "getFile", file_id: file_id),
+ path = "https://api.telegram.org/file/bot#{t}/#{file["file_path"]}",
+ {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- HTTPoison.get(path),
+ <<smol_body::binary-size(20), _::binary>> = body,
+ {:ok, magic} <- GenMagic.Pool.perform(LSG.GenMagic, {:bytes, smol_body}),
+ bucket = Application.get_env(:lsg, :s3, []) |> Keyword.get(:bucket),
+ ext = Path.extname(file["file_path"]),
+ s3path = "#{account.id}/#{file_unique_id}#{ext}",
+ Telegram.Api.request(t, "editMessageText", chat_id: chat_id, message_id: m_id, text: "Uploading...", reply_markup: %{}),
+ s3req = ExAws.S3.put_object(bucket, s3path, body, acl: :public_read, content_type: magic.mime_type),
+ {:ok, _} <- ExAws.request(s3req)
+ do
+ path = "https://s3.wasabisys.com/#{bucket}/#{s3path}"
+ sent = for {net, chan} <- target do
+ user = IRC.UserTrack.find_by_account(net, account)
+ nick = if(user, do: user.nick, else: account.name)
+ txt = "#{nick} sent#{type}#{text} #{path}"
+ IRC.Connection.broadcast_message(net, chan, txt)
+ "#{net}/#{chan}"
+ end
+ if caption = op["caption"], do: as_irc_message(chat_id, caption, account)
+ text = "Sent on " <> Enum.join(sent, ", ") <> " !"
+ Telegram.Api.request(t, "editMessageText", chat_id: chat_id, message_id: m_id, text: "Sent!", reply_markup: %{})
+ else
+ error ->
+ Telegram.Api.request(t, "editMessageText", chat_id: chat_id, message_id: m_id, text: "Something failed.", reply_markup: %{})
+ Logger.error("Failed upload from Telegram: #{inspect error}")
+ end
+ end)
+ end
+ end
+
+ def handle_update(_, %{"message" => m = %{"chat" => %{"id" => id, "type" => "private"}, "text" => text}}) do
+ account = IRC.Account.find_meta_account("telegram-id", id)
+ if account do
+ as_irc_message(id, text, account)
+ end
+ end
+
+ def send_message(id, text) do
+ token = Keyword.get(Application.get_env(:lsg, :telegram, []), :key)
+ Telegram.Api.request(token, "sendMessage", chat_id: id, text: text)
+ end
+
+ def handle_update(token__, m) do
+ Logger.debug("Unhandled update: #{inspect m}")
+ end
+
+ defp as_irc_message(id, text, account) do
+ reply_fun = fn(text) -> send_message(id, text) end
+ trigger_text = cond do
+ String.starts_with?(text, "/") ->
+ "/"<>text = text
+ "!"<>text
+ Enum.any?(IRC.Connection.triggers(), fn({trigger, _}) -> String.starts_with?(text, trigger) end) ->
+ text
+ true ->
+ "!"<>text
+ end
+ message = %IRC.Message{
+ transport: :telegram,
+ network: "telegram",
+ channel: nil,
+ text: text,
+ account: account,
+ sender: %ExIRC.SenderInfo{nick: account.name},
+ replyfun: reply_fun,
+ trigger: IRC.Connection.extract_trigger(trigger_text)
+ }
+ IO.puts("converted telegram to message: #{inspect message}")
+ IRC.Connection.publish(message, ["message:private", "message:telegram"])
+ message
+ end
+
+ command "start" do
+ text = "Hello to beautte! Query the bot on IRC and say \"enable-telegram\" to continue."
+ request("sendMessage", chat_id: update["chat"]["id"],
+ text: text)
+ end
+
+ command "start", args do
+ IO.inspect(update)
+ key = "none"
+ account = IRC.Account.find_meta_account("telegram-validation-code", String.downcase(key))
+ text = if account do
+ net = IRC.Account.get_meta(account, "telegram-validation-target")
+ IRC.Account.put_meta(account, "telegram-id", update["chat"]["id"])
+ IRC.Account.delete_meta(account, "telegram-validation-code")
+ IRC.Account.delete_meta(account, "telegram-validation-target")
+ IRC.Connection.broadcast_message(net, account, "Telegram account added!")
+ "Yay! Linked to account #{account.name}\n\nThe bot doesn't work by sending telegram commands, just send what you would usually send on IRC."
+ else
+ "Token invalid"
+ end
+ request("sendMessage", chat_id: update["chat"]["id"], text: text)
+ end
+
+ command unknown do
+ request("sendMessage", chat_id: update["chat"]["id"],
+ text: "Hey! You sent me a command #{unknown} #{inspect update}")
+ end
+
+ message do
+ request("sendMessage", chat_id: update["chat"]["id"],
+ text: "Hey! You sent me a message: #{inspect update}")
+ end
+end
+
+