From 4f4ad95ac40263d2d4128632e9b0df9f8e7eb74d Mon Sep 17 00:00:00 2001 From: actually akac <38866219+actually-akac@users.noreply.github.com> Date: Wed, 7 Sep 2022 19:48:50 +0200 Subject: [PATCH] Version 1.1.4 - Added a documentation XML file - Updated some variable and method names - The constructor of YachtsClient had its identity and cache period arguments switched - Bumped Discord.net for the example project from 3.7.2 to 3.8.0 - Minor general code changes --- Example/Example.csproj | 2 +- Example/Program.cs | 16 ++-- README.md | 117 +++++++++++++++++------------ SinkingYachts/Connection.cs | 50 +++++++++--- SinkingYachts/README_NuGet.md | 88 +++++++++++++++------- SinkingYachts/SinkingYachts.cs | 55 +++++++++----- SinkingYachts/SinkingYachts.csproj | 7 +- 7 files changed, 217 insertions(+), 118 deletions(-) diff --git a/Example/Example.csproj b/Example/Example.csproj index 7af21f2..5488089 100644 --- a/Example/Example.csproj +++ b/Example/Example.csproj @@ -6,7 +6,7 @@ - + diff --git a/Example/Program.cs b/Example/Program.cs index df4368f..7c19cad 100644 --- a/Example/Program.cs +++ b/Example/Program.cs @@ -16,7 +16,7 @@ public static class Program public static readonly StorageMode Mode = StorageMode.LocalWS; - private static readonly YachtsClient Yachts = new(Mode, 3, "Example Bot"); + private static readonly YachtsClient Yachts = new(Mode, "Example Bot", 3); private static readonly string Token = Environment.GetEnvironmentVariable("BOT_TOKEN"); @@ -61,9 +61,9 @@ public static async Task Main() public static async Task Ready() { - await Logger.Log("Bot", $"Bot is ready to protect your server from {await Yachts.DatabaseSize()} phishing domains", LogSeverity.Info); + await Logger.Log("Bot", $"Ready to protect your server from {await Yachts.GetDatabaseSize()} phishing domains", LogSeverity.Info); - Change[] changes = await Yachts.Recent(TimeSpan.FromDays(1)); + Change[] changes = await Yachts.GetRecent(TimeSpan.FromDays(1)); int added = changes.Count(x => x.Type == ChangeType.Add); int deleted = changes.Count(x => x.Type == ChangeType.Delete); @@ -78,11 +78,11 @@ public static async Task OnMessageReceived(SocketMessage msg) if (msg.Channel is not SocketTextChannel) return; if (msg.Author.IsBot) return; - if (await Yachts.IsPhishing(msg.Content)) - { - await msg.DeleteAsync(); - await msg.Channel.SendMessageAsync("Phishing links are not allowed."); - } + bool isPhishing = await Yachts.IsPhishing(msg.Content); + if (!isPhishing) return; + + await msg.DeleteAsync(); + await msg.Channel.SendMessageAsync($"{msg.Author.Mention}, phishing links are not allowed."); } } } \ No newline at end of file diff --git a/README.md b/README.md index 3db9419..8ccdf34 100644 --- a/README.md +++ b/README.md @@ -9,76 +9,97 @@ ## Usage -This library can be downloaded as the package `SinkingYachts`. The main class is called `YachtsClient`. +Available on NuGet as `SinkingYachts`, methods are available under the public class `YachtsClient`. https://www.nuget.org/packages/SinkingYachts ## Features +- Made with **.NET 6** - Fully async -- Access to a Discord-related phishing database of over `13 300` confirmed malicious domains +- Access to a Discord-related phishing database of over `15 500` confirmed malicious domains - Regex matching of domains and automatic phishing detection - Different modes for storing and loading phishing domains - Instant updates through **WebSocket events** -- Domain whitelisting to prevent false positives -- Customizable caching to decrease load +- Domain whitelisting to decrease false positives +- Customizable caching to decrease load + +## Example Project +Under the `Example` directory you can find a working demo Discord bot that implements this library. +```rust +07.09. 19:13:59 [Discord] Discord.Net v3.8.0 (API v9) +07.09. 19:13:59 [Gateway] Connecting +07.09. 19:14:01 [Gateway] Connected +07.09. 19:14:02 [Bot] Ready to protect your server from 15601 phishing domains +07.09. 19:14:02 [Bot] Domains added within the past day: 8 +07.09. 19:14:02 [Bot] Domains deleted within the past day: 0 +07.09. 19:14:02 [Gateway] Ready +``` + +## Code Samples + +### Check message content +```csharp +bool isPhishing = await Yachts.IsPhishing("hello https://hypesquadacademy-apply.ml"); +//👉 True +``` + +### Check a domain +```csharp +bool isPhishing = await Yachts.IsPhishingDomain("warning-selectioneventhype.gq"); +//👉 True +``` + +### Get the latest domains +```csharp +string[] domains = (await Yachts.GetRecent(TimeSpan.FromDays(1))).Where(x => x.Type == ChangeType.Add).SelectMany(x => x.Domains).ToArray(); +//👉 steamcommunitysiv.top, wvwww-roblox.com, discord-download.win, steamcoumunity.eu, streamcummonity.com, streamcommunity.org, join-event-hypesquad.com, steamcommunityzowe.top +``` + +### Get the database size +```csharp +int size = await Yachts.GetDatabaseSize(); +//👉 15601 +``` ## Available methods -- Task `Recent`(TimeSpan time) -- Task `Recent`(int seconds) -- Task `IsPhishing`(string content) -- Task `IsPhishingDomain`(string domain) -- Task `DatabaseSize`() -- Task `GetPhishingDomains`() +- Task GetRecent(TimeSpan time) +- Task GetRecent(int seconds) +- Task IsPhishing(string content) +- Task IsPhishingDomain(string domain) +- Task GetDatabaseSize() +- Task GetPhishingDomains() ## Available events (requires `StorageMode.LocalWS`) -- EventHandler\ `DomainAdded` -- EventHandler\ `DomainDeleted` +- EventHandler\ DomainAdded +- EventHandler\ DomainDeleted ## Statistics from the past week | Date | New domains found | | :---: | :---: | -| 0.0.0 | + `0` | -| 0.0.0 | + `0` | -| 0.0.0 | + `0` | -| 0.0.0 | + `0` | -| 0.0.0 | + `0` | -| 23.06.2022 | + `33` | -| 24.06.2022 | + `24` | +| 31.08.2022 | + `23` | +| 01.09.2022 | + `10` | +| 02.09.2022 | + `23` | +| 03.09.2022 | + `25` | +| 04.09.2022 | + `3` | +| 05.09.2022 | + `18` | +| 06.09.2022 | + `5` | ## Recently flagged domains ```ruby -steamcommunityzivc.top -www-robloxa.com -wwzw-robloxs.com -www-roblox.com.ru -discoradnitro.xyz -hype-squad-vote.gq -www.discordpolicy.repl.co -wmw-roblox.com -hype-events-badges.gq -wwu-roblox.com -discrod-egift.com +steamcommunityzowe.top +sleamtlade-ofler.xyz +vww-roblox.ga +wwwwv-roblox.com +roblox-profiles.gq ``` -## Example -Under the `Example` folder you can find a demo Discord bot that implements this library. -```rust -18.06. 20:09:38 [Discord] Discord.Net v3.6.0 (API v9) -18.06. 20:09:38 [Gateway] Connecting -18.06. 20:09:40 [Gateway] Connected -18.06. 20:09:40 [Bot] Bot is ready to protect your server from 13326 phishing domains -18.06. 20:09:40 [Bot] Domains added within the past day: 111 -18.06. 20:09:40 [Bot] Domains deleted within the past day: 0 -18.06. 20:09:40 [Gateway] Ready -``` - -## Unknown domains -Found a Discord/Steam phishing domain that isn't yet present in the database? Send it into the `#domain-reports` channel on our Discord server or open an **issue**. +## Missing domains +Found a Discord/Steam phishing domain that isn't yet present in the database? Send it into the `#domain-reports` channel on our Discord server or open an **issue** in this repository. -## Links -Need help, want to discuss phishing or have a suggestion? Feel free to join our Discord server: https://discord.gg/cT6eQjWW8H +## Resources +Need help, want to discuss phishing or have a suggestion? Feel free to join our Discord server: https://discord.gg/d63pvY28HU (temporarily closed) Official website: https://sinking.yachts
-Email: sinkingyachts@gmail.com
+Email: admin@fishfish.gg, sinkingyachts@gmail.com
GitHub: https://github.com/SinkingYachts
-Blog: https://sinking.yachts/blog/
+Blog: https://sinking.yachts/blog/
\ No newline at end of file diff --git a/SinkingYachts/Connection.cs b/SinkingYachts/Connection.cs index 214295b..aeb7921 100644 --- a/SinkingYachts/Connection.cs +++ b/SinkingYachts/Connection.cs @@ -8,42 +8,69 @@ namespace SinkingYachts { + /// + /// The class for connecting and receiving messages from the real-time WebSocket server. + /// public class Connection { - public const string URL = "wss://phish.sinking.yachts/feed"; - public const int ReconnectionInterval = 10000; + /// + /// The WebSocket URI to connect to. + /// + public static readonly Uri Feed = new("wss://phish.sinking.yachts/feed"); + + /// + /// How long to wait before reconnecting after a connection is lost. + /// + public const int ReconnectionDelay = 10000; private ClientWebSocket WS; private readonly CancellationTokenSource Source = new(); + /// + /// Whether there is currently a connection to the phishing feed. + /// public bool Connected = false; + /// + /// Executes whenever a phishing domain is added into the database. + /// public EventHandler DomainAdded; + + /// + /// Executes whenever a phishing domain is removed from the database. + /// public EventHandler DomainDeleted; - private readonly string _identity; + private readonly string Identity; + /// + /// Default constructor for the connection class. + /// + /// public Connection(string identity) { - _identity = identity; + Identity = identity; Connect(); } + /// + /// Connects to the remote WebSocket server to start receiving updates. + /// public async void Connect() { Connected = false; WS = new ClientWebSocket(); - WS.Options.SetRequestHeader("X-Identity", _identity); + WS.Options.SetRequestHeader("X-Identity", Identity); try { - await WS.ConnectAsync(new Uri(URL), Source.Token); + await WS.ConnectAsync(Feed, Source.Token); } catch { Connected = false; - await Task.Delay(ReconnectionInterval); + await Task.Delay(ReconnectionDelay); Connect(); return; } @@ -62,8 +89,8 @@ public async void Connect() WebSocketReceiveResult result = await WS.ReceiveAsync(bytesReceived, Source.Token); offset += result.Count; - if (result.EndOfMessage) - break; + + if (result.EndOfMessage) break; } catch { break; }; } @@ -72,10 +99,13 @@ public async void Connect() } Connected = false; - await Task.Delay(ReconnectionInterval); + await Task.Delay(ReconnectionDelay); Connect(); } + /// + /// Called when a WebSocket message is received. + /// public void OnMessage(string msg) { Change data; diff --git a/SinkingYachts/README_NuGet.md b/SinkingYachts/README_NuGet.md index 6f41ec0..015f0b4 100644 --- a/SinkingYachts/README_NuGet.md +++ b/SinkingYachts/README_NuGet.md @@ -4,49 +4,79 @@ A C# library for detecting Discord/Steam phishing links using the Sinking Yachts API. + ## Usage -Everything is located within the `SinkingYachts` NuGet package, the main class is called `YachtsClient`. +Available on NuGet as `SinkingYachts`, methods are available under the public class `YachtsClient`. + +https://www.nuget.org/packages/SinkingYachts ## Features +- Made with **.NET 6** - Fully async -- Access to a Discord-related phishing database of over `13 300` confirmed malicious domains +- Access to a Discord-related phishing database of over `15 500` confirmed malicious domains - Regex matching of domains and automatic phishing detection - Different modes for storing and loading phishing domains - Instant updates through **WebSocket events** -- Domain whitelisting to prevent false positives -- Customizable caching to decrease load +- Domain whitelisting to decrease false positives +- Customizable caching to decrease load + +## Example Project +Under the `Example` directory you can find a working demo Discord bot that implements this library. +```rust +07.09. 19:13:59 [Discord] Discord.Net v3.8.0 (API v9) +07.09. 19:13:59 [Gateway] Connecting +07.09. 19:14:01 [Gateway] Connected +07.09. 19:14:02 [Bot] Ready to protect your server from 15601 phishing domains +07.09. 19:14:02 [Bot] Domains added within the past day: 8 +07.09. 19:14:02 [Bot] Domains deleted within the past day: 0 +07.09. 19:14:02 [Gateway] Ready +``` + +## Code Samples + +### Check message content +```csharp +bool isPhishing = await Yachts.IsPhishing("hello https://hypesquadacademy-apply.ml"); +//👉 True +``` + +### Check a domain +```csharp +bool isPhishing = await Yachts.IsPhishingDomain("warning-selectioneventhype.gq"); +//👉 True +``` + +### Get the latest domains +```csharp +string[] domains = (await Yachts.GetRecent(TimeSpan.FromDays(1))).Where(x => x.Type == ChangeType.Add).SelectMany(x => x.Domains).ToArray(); +//👉 steamcommunitysiv.top, wvwww-roblox.com, discord-download.win, steamcoumunity.eu, streamcummonity.com, streamcommunity.org, join-event-hypesquad.com, steamcommunityzowe.top +``` + +### Get the database size +```csharp +int size = await Yachts.GetDatabaseSize(); +//👉 15601 +``` ## Available methods -- Task `Recent`(TimeSpan time) -- Task `Recent`(int seconds) -- Task `IsPhishing`(string content) -- Task `IsPhishingDomain`(string domain) -- Task `DatabaseSize`() -- Task `GetPhishingDomains`() +- Task GetRecent(TimeSpan time) +- Task GetRecent(int seconds) +- Task IsPhishing(string content) +- Task IsPhishingDomain(string domain) +- Task GetDatabaseSize() +- Task GetPhishingDomains() ## Available events (requires `StorageMode.LocalWS`) -- EventHandler\ `DomainAdded` -- EventHandler\ `DomainDeleted` +- EventHandler\ DomainAdded +- EventHandler\ DomainDeleted -## Example -Under the `Example` folder you can find a demo Discord bot that implements this library. -```rust -18.06. 20:09:38 [Discord] Discord.Net v3.6.0 (API v9) -18.06. 20:09:38 [Gateway] Connecting -18.06. 20:09:40 [Gateway] Connected -18.06. 20:09:40 [Bot] Bot is ready to protect your server from 13326 phishing domains -18.06. 20:09:40 [Bot] Domains added within the past day: 111 -18.06. 20:09:40 [Bot] Domains deleted within the past day: 0 -18.06. 20:09:40 [Gateway] Ready -``` - -## Unknown domains -Found a Discord/Steam phishing domain that isn't yet present in the database? Send it into the `#domain-reports` channel on our Discord server or open an **issue**. +## Missing domains +Found a Discord/Steam phishing domain that isn't yet present in the database? Send it into the `#domain-reports` channel on our Discord server or open an **issue** in this repository. -## Links -Need help, want to discuss phishing or have a suggestion? Feel free to join our Discord server: https://discord.gg/cT6eQjWW8H +## Resources +Need help, want to discuss phishing or have a suggestion? Feel free to join our Discord server: https://discord.gg/d63pvY28HU (temporarily closed) * Official website: https://sinking.yachts -* Email: sinkingyachts@gmail.com +* Email: admin@fishfish.gg, sinkingyachts@gmail.com * GitHub: https://github.com/SinkingYachts * Blog: https://sinking.yachts/blog/ \ No newline at end of file diff --git a/SinkingYachts/SinkingYachts.cs b/SinkingYachts/SinkingYachts.cs index 86d228e..4ccf19d 100644 --- a/SinkingYachts/SinkingYachts.cs +++ b/SinkingYachts/SinkingYachts.cs @@ -39,9 +39,15 @@ public enum StorageMode /// public enum ChangeType { + /// + /// Domain add event. + /// [JsonPropertyName("add")] Add, + /// + /// Domain delete event. + /// [JsonPropertyName("delete")] Delete } @@ -106,11 +112,18 @@ public class YachtsClient private static Connection Con; - private readonly string _identity; - private readonly TimeSpan _cachePeriod; - private readonly StorageMode _mode; + private readonly string Identity; + private readonly TimeSpan CachePeriod; + private readonly StorageMode Mode; + /// + /// Executes whenever a phishing domain is added into the database. + /// public EventHandler DomainAdded; + + /// + /// Executes whenever a phishing domain is deleted from the database. + /// public EventHandler DomainDeleted; /// @@ -119,23 +132,25 @@ public class YachtsClient /// The domain storage mode to use. /// A short string identifying your bot application. By default this is the name of your project. /// How long in hours should be API responses cached for. - public YachtsClient(StorageMode mode, int cachePeriodHours = 3, string identity = null) + public YachtsClient(StorageMode mode, string identity = null, int cachePeriodHours = 3) { - _mode = mode; - _identity = $"https://github.com/actually-akac/SinkingYachts | {identity ?? Assembly.GetEntryAssembly().GetName().Name}"; - _cachePeriod = TimeSpan.FromHours(cachePeriodHours); + Mode = mode; + Identity = $"https://github.com/actually-akac/SinkingYachts | {identity ?? Assembly.GetEntryAssembly().GetName().Name}"; + CachePeriod = TimeSpan.FromHours(cachePeriodHours); Client = new(); - Client.DefaultRequestHeaders.Add("X-Identity", _identity); + Client.DefaultRequestHeaders.Add("X-Identity", Identity); - switch (_mode) + switch (Mode) { case StorageMode.Local: { UpdateCache(); - Refresher = new(); - Refresher.Interval = RefreshInterval; + Refresher = new() + { + Interval = RefreshInterval + }; Refresher.Elapsed += (o, e) => UpdateCache(); Refresher.Start(); @@ -145,12 +160,14 @@ public YachtsClient(StorageMode mode, int cachePeriodHours = 3, string identity { UpdateCache(); - Refresher = new(); - Refresher.Interval = RefreshInterval; + Refresher = new() + { + Interval = RefreshInterval + }; Refresher.Elapsed += (o, e) => UpdateCache(); Refresher.Start(); - Con = new Connection(_identity); + Con = new Connection(Identity); Con.DomainAdded += (sender, domain) => Cache[domain] = true; Con.DomainAdded += (sender, domain) => DomainAdded(sender, domain); @@ -224,7 +241,7 @@ public async Task IsPhishingDomain(string domain) output = bool.Parse(content); Cache[domain] = output; - Task remover = Task.Delay(_cachePeriod).ContinueWith(x => + Task remover = Task.Delay(CachePeriod).ContinueWith(x => { Cache.Remove(domain); }); @@ -249,7 +266,7 @@ public async Task GetPhishingDomains() /// /// Fetches the total amount of flagged domains in the database. /// - public async Task DatabaseSize() + public async Task GetDatabaseSize() { HttpResponseMessage res = await Client.GetAsync($"{Api}/v{Version}/dbsize"); string content = await res.Content.ReadAsStringAsync(); @@ -267,7 +284,7 @@ public async Task DatabaseSize() /// /// Fetches the domains added or deleted within the last X seconds. /// - public async Task Recent(int seconds) + public async Task GetRecent(int seconds) { if (seconds > 604800) throw new ArgumentException("Maximum value is 604800 seconds (7 days).", nameof(seconds)); if (seconds <= 0) throw new ArgumentException("Argument has to be positive.", nameof(seconds)); @@ -293,9 +310,9 @@ public async Task Recent(int seconds) /// /// Fetches the domains added or deleted within the provided TimeSpan. /// - public async Task Recent(TimeSpan time) + public async Task GetRecent(TimeSpan time) { - return await Recent((int)time.TotalSeconds); + return await GetRecent((int)time.TotalSeconds); } } } \ No newline at end of file diff --git a/SinkingYachts/SinkingYachts.csproj b/SinkingYachts/SinkingYachts.csproj index e4e8028..30254f6 100644 --- a/SinkingYachts/SinkingYachts.csproj +++ b/SinkingYachts/SinkingYachts.csproj @@ -3,7 +3,9 @@ net6.0 SinkingYachts - 1.0.4 + 1.1.4 + 1.1.4 + 1.1.4 akac akac SinkingYachts @@ -15,10 +17,9 @@ https://github.com/actually-akac/SinkingYachts git phishing; phish; scam; anti-phishing; anti-scam; discord; steam; sinking-yachts - 1.0.4 - 1.0.4 en MIT + true