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 | |
parent | bleh (diff) |
pouet
Diffstat (limited to 'lib/lsg')
-rw-r--r-- | lib/lsg/application.ex | 7 | ||||
-rw-r--r-- | lib/lsg/auth_token.ex | 59 | ||||
-rw-r--r-- | lib/lsg/telegram.ex | 254 |
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 + + |