Skip to content
This repository has been archived by the owner on Dec 3, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1 from druffko/build-poc
Browse files Browse the repository at this point in the history
Build poc
  • Loading branch information
druffko authored Sep 29, 2024
2 parents 798ec31 + 5275840 commit 6d39377
Show file tree
Hide file tree
Showing 11 changed files with 524 additions and 1 deletion.
10 changes: 10 additions & 0 deletions App.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="kaelus.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>
24 changes: 24 additions & 0 deletions App.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;

namespace kaelus
{
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}

public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow();
}

base.OnFrameworkInitializationCompleted();
}
}
}
Binary file added Assets/kaelus-icon.ico
Binary file not shown.
186 changes: 186 additions & 0 deletions Engine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;

namespace kaelus
{
internal class Engine
{
#region statics

internal static HashSet<string> foundEmails = new HashSet<string>();

internal static string finishedResults = "";

#endregion

#region static methods

internal static void ExtractSourceCode(string url)
{

bool isUrl = IsUrl(url);

if (isUrl)
{

}
else
{
url = "https://" + url;
}

// Scan the main index page and get all links on it
ScanLinks(url);

// Display the collected emails at the end
DisplayCollectedEmails();
}

public static string kaelusScan(string url)
{
bool isUrl = IsUrl(url);

if (isUrl)
{

}
else
{
url = "https://" + url;
}

// Scan the main index page and get all links on it
ScanLinks(url);

// Display the collected emails at the end
DisplayCollectedEmails();
return finishedResults;
}

internal static void ScanLinks(String url)
{
List<string> links = new List<string>();

// Fetch page source
string pageContent = FetchPageContent(url);

if (string.IsNullOrEmpty(pageContent))
{
Console.WriteLine("No content found on the page.");
return;
}

// Use HtmlAgilityPack to parse the HTML and find all links
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(pageContent);

foreach (HtmlNode link in doc.DocumentNode.SelectNodes("//a[@href]"))
{
string href = link.GetAttributeValue("href", string.Empty);

// If it's a relative link, convert it to an absolute URL
Uri baseUri = new Uri(url);
Uri fullUri = new Uri(baseUri, href);

if (fullUri.Host == baseUri.Host) // Ensure it's the same domain
{
links.Add(fullUri.ToString());
}
}

// Scan each link for email addresses
foreach (string link in links)
{
//Console.WriteLine(kaleidolib.lib.Formatting.dim($"Scanning {link} for email addresses..."));
string content = FetchPageContent(link);
if (!string.IsNullOrEmpty(content))
{
GetMails(content);
}
}
}

// Method to fetch the page content
internal static string FetchPageContent(string url)
{
try
{
using (HttpClient client = new())
{
HttpResponseMessage response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsStringAsync().Result;
}
else
{
Console.WriteLine($"Failed to fetch {url}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error fetching page content: {ex.Message}");
}
return string.Empty;
}

// Method to collect emails found on a page
internal static void GetMails(String sourceCode)
{
string emailPattern = @"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b";

// Use Regex.Matches to find all occurrences of email addresses in the input string
MatchCollection matches = Regex.Matches(sourceCode, emailPattern, RegexOptions.IgnoreCase);

if (matches.Count > 0)
{
foreach (Match match in matches)
{
// Add to the HashSet to ensure uniqueness
foundEmails.Add(match.Value);
}
}
}

// Display collected emails and filter duplicates
internal static void DisplayCollectedEmails()
{
if (foundEmails.Count > 0)
{
//Console.WriteLine(Color.green("Good news! I found the following unique email addresses:"));
foreach (var email in foundEmails)
{
Console.WriteLine(email);
finishedResults = finishedResults + email + "\n";
}
}
else
{
//Console.WriteLine(Color.red("No email addresses found."));
finishedResults = "No email addresses found";
}
}

static bool IsUrl(string input)
{
return Uri.TryCreate(input, UriKind.Absolute, out Uri result) &&
(result.Scheme == Uri.UriSchemeHttp || result.Scheme == Uri.UriSchemeHttps);
}

public static String GetTimestamp(DateTime value)
{
return value.ToString("yyyyMMddHHmmss");
}

#endregion
}
}
33 changes: 33 additions & 0 deletions MainWindow.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="250"
Width="500" Height="250"
x:Class="kaelus.MainWindow"
CanResize="False"
WindowStartupLocation="CenterScreen"
Title="KAELUS - Ultimate Email Extractor.">

<Grid Margin="10,10,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<Label Grid.Row="0" Grid.Column="0">Domain to scan</Label>
<TextBox x:Name="URLBox" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,20" Text=""/>
<TextBox x:Name="ResultBox" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" AcceptsReturn="True" TextWrapping="Wrap" IsReadOnly="True" Text=""/>
<ProgressBar x:Name="ScanProgress" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" Margin="0 10" Minimum="0" Maximum="100" Value="0" ShowProgressText="True" IsVisible="False"/>
<Button Click="ShowHelp" Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left" Margin="0,20,0,0"> Help</Button>
<Button Click="StartScan" Grid.Row="4" Grid.Column="2" HorizontalAlignment="Right" Margin="0,20,0,0"> Start</Button>
</Grid>
</Window>
78 changes: 78 additions & 0 deletions MainWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using MsBox.Avalonia;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace kaelus
{
public partial class MainWindow : Window
{

public string resultBoxText;

public MainWindow()
{
InitializeComponent();
}
public async void StartScan(object sender, RoutedEventArgs args)
{
string url = URLBox.Text;

// Create a CancellationTokenSource to manage the cancellation
var cancellationTokenSource = new CancellationTokenSource();

// Run both tasks concurrently
var progressTask = makeProgress(cancellationTokenSource.Token);
var resultTask = RunKaelusScanAsync(url);

// When the resultTask completes, cancel the progressTask
await resultTask;
cancellationTokenSource.Cancel();

// Await progressTask to ensure proper cleanup
try
{
await progressTask;
}
catch (OperationCanceledException)
{
ScanProgress.IsVisible = false;
}
}

public void ShowHelp(object sender, RoutedEventArgs args)
{
var helpBox = MessageBoxManager.GetMessageBoxStandard("KAELUS Help", "Just enter the desired URL and click Start. KAELUS will do the rest", MsBox.Avalonia.Enums.ButtonEnum.Ok);
var result = helpBox.ShowAsPopupAsync(this);
}

public async Task makeProgress(CancellationToken cancellationToken)
{
// Fake Progress bar (to indicate work)
ScanProgress.Value = 0;
ScanProgress.IsVisible = true;
ResultBox.Text = "Scanning for email addresses...";

while (ScanProgress.Value < ScanProgress.Maximum)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}

await Task.Delay(2000, cancellationToken);
ScanProgress.Value = Math.Min(ScanProgress.Value + 1, ScanProgress.Maximum);
}

}

private async Task RunKaelusScanAsync(string url)
{
string result = await Task.Run(() => Engine.kaelusScan(url));

ResultBox.Text = result;
}
}
}
22 changes: 22 additions & 0 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Avalonia;
using System;

namespace kaelus
{
internal class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);

// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}
}
Loading

0 comments on commit 6d39377

Please sign in to comment.