diff --git a/fs24bot3/Backend/Basic.cs b/fs24bot3/Backend/Basic.cs index 2418700..b334a0c 100644 --- a/fs24bot3/Backend/Basic.cs +++ b/fs24bot3/Backend/Basic.cs @@ -61,4 +61,9 @@ public async void Process() } } } + + public Task EnsureAuthorization(User user) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/fs24bot3/Backend/IMessagingClient.cs b/fs24bot3/Backend/IMessagingClient.cs index 1810ed8..5961ee0 100644 --- a/fs24bot3/Backend/IMessagingClient.cs +++ b/fs24bot3/Backend/IMessagingClient.cs @@ -17,7 +17,6 @@ public interface IMessagingClient public Bot BotContext { get; } public Dictionary Fmt { get; } - public void SetupNick(string nickname) { } public void JoinChannel(string name) { @@ -28,13 +27,14 @@ public void PartChannel(string name) throw new NotImplementedException(); } - public Task SendMessage(string channel, string message) - { - throw new NotImplementedException(); - } - + public Task SendMessage(string channel, string message); public void Process() { BotContext.ProccessInfinite(); } + + public Task EnsureAuthorization(User user) + { + return Task.FromResult(true); + } } \ No newline at end of file diff --git a/fs24bot3/Backend/IRC.cs b/fs24bot3/Backend/IRC.cs index dd11329..6eeb304 100644 --- a/fs24bot3/Backend/IRC.cs +++ b/fs24bot3/Backend/IRC.cs @@ -72,7 +72,7 @@ public Irc() Log.Warning("IRC backend was unable to find configuration file, I will create it for you"); File.WriteAllText(ConfigPath, Toml.FromModel(Config)); } - + Fmt = new Dictionary { // add irc colors @@ -98,15 +98,15 @@ public Irc() SetupNick(Config.Name); - BotClient = new Client(new NetIRC.User(Name, "Sopli IRC 3.0"), + BotClient = new Client(new NetIRC.User(Name, "Sopli IRC 3.0"), new TcpClientConnection(Config.Network, Config.Port)); - + BotClient.RawDataReceived += Client_OnRawDataReceived; BotClient.IRCMessageParsed += Client_OnIRCMessageParsed; BotClient.RegistrationCompleted += Client_OnRegister; } - - + + private async void Client_OnIRCMessageParsed(Client client, ParsedIRCMessage message) { if (message.IRCCommand == IRCCommand.PRIVMSG) @@ -129,7 +129,7 @@ private async void Client_OnIRCMessageParsed(Client client, ParsedIRCMessage mes if (message.NumericReply == IRCNumericReply.ERR_NICKNAMEINUSE) { - SetupNick(Name + new Random().Next(int.MinValue, int.MaxValue)); + SetupNick(Name + new Random().Next(int.MinValue, int.MaxValue)); } if (message.NumericReply == IRCNumericReply.ERR_PASSWDMISMATCH) @@ -140,8 +140,8 @@ private async void Client_OnIRCMessageParsed(Client client, ParsedIRCMessage mes if (message.IRCCommand == IRCCommand.KICK && message.Parameters[1] == Name) { Log.Warning("I've got kick from {0} rejoining...", message.Prefix); - await client.SendRaw("JOIN " + message.Parameters[0]); - await SendMessage(message.Parameters[0], "За что?"); + await client.SendRaw("JOIN " + message.Parameters[0]); + await SendMessage(message.Parameters[0], "За что?"); } } @@ -168,14 +168,14 @@ public async void JoinChannel(string name) { await BotClient.SendRaw("JOIN " + name); } - + public async void PartChannel(string name) { await BotClient.SendRaw("PART " + name); } public void Process() - { + { Log.Information("Connecting to: {0}:{1}", Config.Network, Config.Port); Task.Run(() => BotClient.ConnectAsync()); BotContext.ProccessInfinite(); @@ -211,11 +211,56 @@ await BotClient.SendAsync(new PrivMsgMessage(channel, $"Слишком жест if (count > 4) { - string link = await InternetServicesHelper.UploadToTrashbin(MessageHelper.StripIRC(message), + string link = await InternetServicesHelper.UploadToTrashbin(MessageHelper.StripIRC(message), "addplain"); await BotClient.SendAsync(new PrivMsgMessage(channel, "Полный вывод: " + link)); return; } } } + + + /// + /// Ensures authorization in IRC + /// + /// + /// + public async Task EnsureAuthorization(Core.User user) + { + var tcs = new TaskCompletionSource(); + ParsedIRCMessageHandler messageHandler = null; + + // ACC returns parsable information about a user's + // login status. Note that on many networks, /whois + // shows similar information faster and more reliably. + // ACC also returns the unique entity ID of the given account. + // The answer is in the form [-> account] ACC , + // where is one of the following: + // 0 - account or user does not exist + // 1 - account exists but user is not logged in + // 2 - user is not logged in but recognized (see ACCESS) + // 3 - user is logged in + // If the account is omitted the user's nick is used and + // the " -> account" portion of the reply is omitted. + // Account * means the account the user is logged in with. + // example: + // Totoro ACC 1 AAAAAXXX + + messageHandler = (client, message) => + { + if (message.Prefix.From == "NickServ") + { + var split = message.Trailing.Split(" "); + + tcs.SetResult(split[2] == "3"); + + BotClient.IRCMessageParsed -= messageHandler; + } + }; + + BotClient.IRCMessageParsed += messageHandler; + + await SendMessage("NickServ", $"ACC {user.Username}"); + return await tcs.Task; + } } \ No newline at end of file diff --git a/fs24bot3/Bot.cs b/fs24bot3/Bot.cs index b2f8bf4..15f2f1a 100644 --- a/fs24bot3/Bot.cs +++ b/fs24bot3/Bot.cs @@ -182,8 +182,10 @@ public async Task ExecuteCommand(MessageGeneric message, string prefix) PProfiler.BeginMeasure("command"); + var auth = await Client.EnsureAuthorization(message.Sender); + var result = - await Service.ExecuteAsync(output, new CommandProcessor.CustomCommandContext(this, in message)); + await Service.ExecuteAsync(output, new CommandProcessor.CustomCommandContext(this, in message, auth)); switch (result) { diff --git a/fs24bot3/Checks/CheckAdmin.cs b/fs24bot3/Checks/CheckAdmin.cs index c3e3aa5..3863cb6 100644 --- a/fs24bot3/Checks/CheckAdmin.cs +++ b/fs24bot3/Checks/CheckAdmin.cs @@ -13,7 +13,7 @@ public override ValueTask CheckAsync(CommandContext _) try { - return context.User.GetUserInfo().Admin > 1 || ConfigurationProvider.Config.Backend == Models.Backend.Basic + return (context.User.GetUserInfo().Admin > 1 && context.IsAuthorizedAction) || ConfigurationProvider.Config.Backend == Models.Backend.Basic ? CheckResult.Successful : CheckResult.Failed("Эта команда только для админов!"); } diff --git a/fs24bot3/Checks/FullAccount.cs b/fs24bot3/Checks/FullAccount.cs index d7b2366..6cf2dcc 100644 --- a/fs24bot3/Checks/FullAccount.cs +++ b/fs24bot3/Checks/FullAccount.cs @@ -9,9 +9,9 @@ public override ValueTask CheckAsync(CommandContext _) { var context = _ as CommandProcessor.CustomCommandContext; - return !context.FromBridge && !context.User.UserIsIgnored() && context.User != null + return !context.FromBridge && !context.User.UserIsIgnored() && context.User != null && context.IsAuthorizedAction ? CheckResult.Successful - : CheckResult.Failed("Эта команда требует аккаунт пользователя fs24_bot!"); + : CheckResult.Failed("Эта команда требует аккаунт fs24_bot и авторизацию через NickServ!"); } public override string ToString() diff --git a/fs24bot3/Commands/NetstalkingCommandsModule.cs b/fs24bot3/Commands/NetstalkingCommandsModule.cs index 0d3b556..8496f72 100644 --- a/fs24bot3/Commands/NetstalkingCommandsModule.cs +++ b/fs24bot3/Commands/NetstalkingCommandsModule.cs @@ -1,12 +1,8 @@ -using fs24bot3.Core; -using fs24bot3.Helpers; +using fs24bot3.Helpers; using fs24bot3.Models; using fs24bot3.QmmandsProcessors; using Newtonsoft.Json; using Qmmands; -using Serilog; -using System; -using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading.Tasks; @@ -17,11 +13,7 @@ public sealed class NetstalkingCommandsModule : ModuleBase