diff --git a/.github/workflows/Windows-GUI.yml b/.github/workflows/Windows-GUI.yml
index 62923c5..e14075b 100644
--- a/.github/workflows/Windows-GUI.yml
+++ b/.github/workflows/Windows-GUI.yml
@@ -25,7 +25,7 @@ jobs:
uses: microsoft/setup-msbuild@v1.1
- name: Setup NuGet
- uses: NuGet/setup-nuget@v1.0.6
+ uses: NuGet/setup-nuget@latest
- name: Restore dependencies
run: nuget restore CheckIP.Windows\CheckIP.sln
diff --git a/.gitignore b/.gitignore
index bccfd0e..14fbd0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -353,6 +353,9 @@ MigrationBackup/
*.keystore
*.pw
+# Rider
+.idea/
+
### macOS ###
# General
.DS_Store
@@ -386,3 +389,59 @@ Temporary Items
# iCloud generated files
*.icloud
CheckIP.Windows/Setup/Output/
+
+
+### macOS ###
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### macOS Patch ###
+# iCloud generated files
+*.icloud
+
+### Xcode ###
+## User settings
+xcuserdata/
+
+## Xcode 8 and earlier
+*.xcscmblueprint
+*.xccheckout
+
+### Xcode Patch ###
+*.xcodeproj/*
+!*.xcodeproj/project.pbxproj
+!*.xcodeproj/xcshareddata/
+!*.xcodeproj/project.xcworkspace/
+!*.xcworkspace/contents.xcworkspacedata
+/*.gcno
+**/xcshareddata/WorkspaceSettings.xcsettings
+
+## Avalonia Build Output
+CheckIP.Avalonia/Output/*
+CheckIP.Avalonia/macOS.Sign/App
+*.pkg
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/App.axaml b/CheckIP.Avalonia/CheckIP.Avalonia/App.axaml
new file mode 100644
index 0000000..a89b9cd
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/App.axaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/App.axaml.cs b/CheckIP.Avalonia/CheckIP.Avalonia/App.axaml.cs
new file mode 100644
index 0000000..fc43310
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/App.axaml.cs
@@ -0,0 +1,42 @@
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using CheckIP.Pages;
+
+namespace CheckIP
+{
+ public partial class App : Application
+ {
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new Main();
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+
+ private void NativeMenuItem_OnClick(object? sender, EventArgs e)
+ {
+ var window = new Window()
+ {
+ Title = "About CheckIP",
+ Content = new About(),
+ MaxHeight = 500,
+ MaxWidth = 400,
+ MinHeight = 500,
+ MinWidth = 400,
+ CanResize = false
+ };
+ window.Show();
+ }
+ }
+}
\ No newline at end of file
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Assets/Logo.svg b/CheckIP.Avalonia/CheckIP.Avalonia/Assets/Logo.svg
new file mode 100644
index 0000000..edb56a2
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Assets/Logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.csproj b/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.csproj
new file mode 100644
index 0000000..7f2b5e7
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.csproj
@@ -0,0 +1,69 @@
+
+
+ WinExe
+ net6.0
+ enable
+ true
+ app.manifest
+ CheckIP.ico
+ CheckIP
+ valnoxy
+ Exploitox
+ Get more information about an IP address.
+ Copyright © 2018 - 2023 Exploitox. All rights reserved.
+ https://github.com/valnoxy/checkip
+ 1.0.0-preview1
+ osx-x64;osx-arm64;linux-x64;linux-arm64
+
+ CheckIP
+ CheckIP
+ dev.valnoxy.checkip
+ 1.0.0-preview1
+ APPL
+ ????
+ CheckIP
+ CheckIP.icns
+ NSApplication
+ true
+ 1.0.0-preview1
+ true
+ CheckIP
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Main.axaml
+
+
+ About.axaml
+
+
+
+
\ No newline at end of file
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.icns b/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.icns
new file mode 100644
index 0000000..f6c83ac
Binary files /dev/null and b/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.icns differ
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.ico b/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.ico
new file mode 100644
index 0000000..39c47ab
Binary files /dev/null and b/CheckIP.Avalonia/CheckIP.Avalonia/CheckIP.ico differ
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Main.axaml b/CheckIP.Avalonia/CheckIP.Avalonia/Main.axaml
new file mode 100644
index 0000000..e2615bd
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Main.axaml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Main.axaml.cs b/CheckIP.Avalonia/CheckIP.Avalonia/Main.axaml.cs
new file mode 100644
index 0000000..643ac91
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Main.axaml.cs
@@ -0,0 +1,63 @@
+using Avalonia.Controls;
+using FluentAvalonia.Core;
+using FluentAvalonia.UI.Controls;
+using System;
+using System.Collections.Generic;
+
+namespace CheckIP
+{
+ public partial class Main : Window
+ {
+ public NavigationView? NavView;
+ public static Main Instance { get; private set; }
+
+ public Main()
+ {
+ InitializeComponent();
+ Instance = this;
+#if DEBUG
+ DebugLabel.Content = "Avalonia Debug build - This is not a production ready build.";
+ DebugLabel.IsVisible = true;
+#endif
+
+ // Build the navigation menu
+ NavView = this.FindControl("RootNavigation");
+
+ var navItems = new List();
+ var footerNavItems = new List();
+ navItems.Add(new NavigationViewItem
+ {
+ Content = "Fetch",
+ IconSource = new SymbolIconSource { Symbol = Symbol.Globe },
+ Tag = "FetchIP"
+ });
+ navItems.Add(new NavigationViewItem
+ {
+ Content = "My IP",
+ IconSource = new SymbolIconSource { Symbol = Symbol.MapPin },
+ Tag = "MyIP"
+ });
+
+ footerNavItems.Add(new NavigationViewItem
+ {
+ Content = "About",
+ IconSource = new SymbolIconSource { Symbol = Symbol.ContactInfo },
+ Tag = "About"
+ });
+
+ NavView!.MenuItems = navItems;
+ NavView!.FooterMenuItems = footerNavItems;
+
+ NavView!.SelectionChanged += NavigationViewChanged!;
+ NavView.SelectedItem = NavView.MenuItems.ElementAt(0);
+ }
+
+ private void NavigationViewChanged(object sender, NavigationViewSelectionChangedEventArgs e)
+ {
+ if (e.SelectedItem is not NavigationViewItem nvi) return;
+ var smpPage = $"CheckIP.Pages.{nvi.Tag}";
+ var pg = Activator.CreateInstance(Type.GetType(smpPage)!);
+ (sender as NavigationView)!.Content = pg;
+ }
+ }
+}
\ No newline at end of file
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Pages/About.axaml b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/About.axaml
new file mode 100644
index 0000000..baaba69
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/About.axaml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+
+
+
+
+
+
+
+
+
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Pages/About.axaml.cs b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/About.axaml.cs
new file mode 100644
index 0000000..e4eb748
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/About.axaml.cs
@@ -0,0 +1,74 @@
+using Avalonia.Controls;
+using System;
+using System.Reflection;
+using Avalonia;
+
+namespace CheckIP.Pages
+{
+ public partial class About : UserControl
+ {
+ public About()
+ {
+ InitializeComponent();
+
+ try
+ {
+ var version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+ var productName = Assembly.GetExecutingAssembly().GetName().Name;
+ ValueVersion.Content = $"{productName} V. {version}";
+ ValueCopyright.Content = GetCopyright();
+
+ var avaloniaInformationalVersion = typeof(AvaloniaObject).Assembly
+ .GetCustomAttribute()!.InformationalVersion;
+ var avaloniaVersion =
+ avaloniaInformationalVersion![
+ ..avaloniaInformationalVersion.IndexOf("+", StringComparison.Ordinal)];
+
+ var fluentAvaloniaVersion = typeof(FluentAvalonia.UI.Controls.NavigationView).Assembly
+ .GetCustomAttribute()!.InformationalVersion;
+
+ var newtonSoftInformationalVersion = typeof(Newtonsoft.Json.JsonConvert).Assembly
+ .GetCustomAttribute()!.InformationalVersion;
+ var newtonsoftVersion =
+ newtonSoftInformationalVersion![
+ ..newtonSoftInformationalVersion.IndexOf("+", StringComparison.Ordinal)];
+
+ AvaloniaVersion.Content = $"Avalonia V. {avaloniaVersion}";
+ FluentAvaloniaVersion.Content = $"FluentAvalonia V. {fluentAvaloniaVersion}";
+ NewtonsoftVersion.Content = $"Newtonsoft.Json V. {newtonsoftVersion}";
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+ }
+
+ private string GetCopyright()
+ {
+ var asm = Assembly.GetExecutingAssembly();
+ var obj = asm.GetCustomAttributes(false);
+ foreach (var o in obj)
+ {
+ if (o.GetType() !=
+ typeof(System.Reflection.AssemblyCopyrightAttribute)) continue;
+ var aca = (AssemblyCopyrightAttribute) o;
+ return aca.Copyright;
+ }
+ return string.Empty;
+ }
+
+ private string GetVersion()
+ {
+ var asm = Assembly.GetExecutingAssembly();
+ var obj = asm.GetCustomAttributes(false);
+ foreach (var o in obj)
+ {
+ if (o.GetType() !=
+ typeof(System.Reflection.AssemblyVersionAttribute)) continue;
+ var aca = (AssemblyVersionAttribute) o;
+ return aca.Version;
+ }
+ return string.Empty;
+ }
+ }
+}
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Pages/FetchIP.axaml b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/FetchIP.axaml
new file mode 100644
index 0000000..def4430
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/FetchIP.axaml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Pages/FetchIP.axaml.cs b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/FetchIP.axaml.cs
new file mode 100644
index 0000000..3f7bfbc
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/FetchIP.axaml.cs
@@ -0,0 +1,173 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Threading;
+using System.Net.Http;
+using System.Net;
+using System.Threading.Tasks;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Newtonsoft.Json.Linq;
+using Avalonia.Platform.Storage;
+using System.Diagnostics;
+
+namespace CheckIP.Pages
+{
+ public partial class FetchIP : UserControl
+ {
+ private static string _myIp;
+
+ public FetchIP()
+ {
+ InitializeComponent();
+ }
+
+ private void FetchIP_Click(object sender, RoutedEventArgs e)
+ {
+ _myIp = IpAddress.Text;
+ Task.Run(ParseIpAddress);
+ }
+
+ private void OnKeyDownHandler(object sender, KeyEventArgs e)
+ {
+ if (e.Key != Key.Return) return;
+ _myIp = IpAddress.Text;
+ Task.Run(ParseIpAddress);
+ }
+
+ private void ParseIpAddress()
+ {
+ // Validate IP
+ var validateIp = IPAddress.TryParse(_myIp, out var ip);
+ if (!validateIp)
+ {
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ErrorLabel.Content = "Error: This is not a valid IP address";
+ });
+ return;
+ }
+
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ErrorLabel.Content = string.Empty;
+ });
+
+ var dataJson = string.Empty;
+ var url = "http://ip-api.com/json/" + _myIp + "?fields=status,message,country,countryCode,city,zip,lat,lon,timezone,isp,as,mobile,proxy,hosting";
+ try
+ {
+ var client = new HttpClient();
+ using var response = client.GetAsync(url).Result;
+ using var content = response.Content;
+ dataJson = content.ReadAsStringAsync().Result;
+ }
+ catch
+ {
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ErrorLabel.Content = "Error: No connection to server";
+ });
+ }
+ dynamic data = JObject.Parse(dataJson);
+
+ // Parse data
+ string status = data.status;
+ string message = data.message;
+ string country = data.country;
+ string countryCode = data.countryCode;
+ string city = data.city;
+ string postal = data.zip;
+ string timezone = data.timezone;
+ string latitude = data.lat;
+ string longitude = data.lon;
+ string isp = data.isp;
+ string asn = data.@as;
+ string mobile = data.mobile;
+ string proxy = data.proxy;
+ string hosting = data.hosting;
+
+ // Check status
+ if (status != "success")
+ {
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ErrorLabel.Content = "Error: " + message;
+ ValueCityCountry.Text = "Unknown";
+ ValuePostal.Text = "Unknown";
+ ValueTimezone.Text = "Unknown";
+ ValueLatitude.Text = "Unknown";
+ ValueLongitude.Text = "Unknown";
+ ValueIsp.Text = "Unknown";
+ ValueAsn.Text = "Unknown";
+ ValueMobile.Text = "Unknown";
+ ValueProxy.Text = "Unknown";
+ ValueHosting.Text = "Unknown";
+ });
+ return;
+ }
+
+ // Set Variable labels
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ValueCityCountry.Text = city + " / " + country + " (" + countryCode + ")";
+ ValuePostal.Text = postal;
+ ValueTimezone.Text = timezone;
+ ValueLatitude.Text = latitude;
+ ValueLongitude.Text = longitude;
+ ValueIsp.Text = isp;
+ ValueAsn.Text = asn;
+ ValueMobile.Text = mobile;
+ ValueProxy.Text = proxy;
+ ValueHosting.Text = hosting;
+ });
+ }
+
+ private void ExportBtn_OnClick(object? sender, RoutedEventArgs e) => Task.Run(ExportTask);
+ private async Task ExportTask()
+ {
+ try
+ {
+ await Dispatcher.UIThread.InvokeAsync(async () =>
+ {
+ var exportString = $@"Report created at {DateTime.Now} for IP {IpAddress.Text}
+
+City / Country: {ValueCityCountry.Text}
+Postal: {ValuePostal.Text}
+Timezone: {ValueTimezone.Text}
+Latitude: {ValueLatitude.Text}
+Longitude: {ValueLongitude.Text}
+ISP or Organization: {ValueIsp.Text}
+ASN: {ValueAsn.Text}
+Is Mobile: {ValueMobile.Text}
+Is Proxy: {ValueProxy.Text}
+Is Hosting: {ValueHosting.Text}
+";
+ var options = new FilePickerSaveOptions
+ {
+ Title = "Export CheckIP Fetch Report",
+ ShowOverwritePrompt = true,
+ DefaultExtension = "txt",
+ FileTypeChoices = new FilePickerFileType[]
+ {
+ new("Text File (*.txt)") { Patterns = new[] { "txt" } }
+ }
+ };
+
+ var selectedFile = await Main.Instance.StorageProvider.SaveFilePickerAsync(options);
+ if (selectedFile.Path != null)
+ {
+ var path = selectedFile.Path;
+ File.WriteAllTextAsync(path.LocalPath, exportString);
+ }
+ });
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.ToString());
+ }
+
+ }
+ }
+}
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Pages/MyIP.axaml b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/MyIP.axaml
new file mode 100644
index 0000000..5185103
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/MyIP.axaml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Pages/MyIP.axaml.cs b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/MyIP.axaml.cs
new file mode 100644
index 0000000..e46f46c
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Pages/MyIP.axaml.cs
@@ -0,0 +1,184 @@
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Threading;
+using Newtonsoft.Json.Linq;
+using System.Net.Http;
+using System.Net;
+using System.Threading.Tasks;
+using System;
+using System.Diagnostics;
+using System.IO;
+using Avalonia.Platform.Storage;
+
+namespace CheckIP.Pages
+{
+ public partial class MyIP : UserControl
+ {
+ private static string _myIp;
+
+ public MyIP()
+ {
+ InitializeComponent();
+ _myIp = Task.Run(_GetIPAddress).GetAwaiter().GetResult();
+ Task.Run(ParseIpAddress);
+ }
+
+ [Obsolete("Will be replaced to a async version soon.")]
+ private static async Task _GetIPAddress()
+ {
+ string result = null;
+ try
+ {
+ result = await Task.Run(() => new WebClient().DownloadString("https://ifconfig.me/ip"));
+ }
+ catch
+ {
+ try
+ {
+ result = await Task.Run(() => new WebClient().DownloadString("https://api.ipify.org"));
+ }
+ catch
+ {
+
+ }
+ }
+
+ return result;
+ }
+
+ private void ParseIpAddress()
+ {
+ // Validate IP
+ var validateIp = IPAddress.TryParse(_myIp, out var ip);
+ if (!validateIp)
+ {
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ErrorLabel.Content = "Error: This is not a valid IP address";
+ }); return;
+ }
+
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ErrorLabel.Content = string.Empty;
+ });
+
+ var dataJson = string.Empty;
+ var url = "http://ip-api.com/json/" + _myIp + "?fields=status,message,country,countryCode,city,zip,lat,lon,timezone,isp,as,mobile,proxy,hosting";
+ try
+ {
+ var client = new HttpClient();
+ using var response = client.GetAsync(url).Result;
+ using var content = response.Content;
+ dataJson = content.ReadAsStringAsync().Result;
+ }
+ catch
+ {
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ErrorLabel.Content = "Error: No connection to server";
+ });
+ }
+ dynamic data = JObject.Parse(dataJson);
+
+ // Parse data
+ string status = data.status;
+ string message = data.message;
+ string country = data.country;
+ string countryCode = data.countryCode;
+ string city = data.city;
+ string postal = data.zip;
+ string timezone = data.timezone;
+ string latitude = data.lat;
+ string longitude = data.lon;
+ string isp = data.isp;
+ string asn = data.@as;
+ string mobile = data.mobile;
+ string proxy = data.proxy;
+ string hosting = data.hosting;
+
+ // Check status
+ if (status != "success")
+ {
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ ErrorLabel.Content = "Error: " + message;
+ IpAddress.Content = "Unknown";
+ ValueCityCountry.Text = "Unknown";
+ ValuePostal.Text = "Unknown";
+ ValueTimezone.Text = "Unknown";
+ ValueLatitude.Text = "Unknown";
+ ValueLongitude.Text = "Unknown";
+ ValueIsp.Text = "Unknown";
+ ValueAsn.Text = "Unknown";
+ ValueMobile.Text = "Unknown";
+ ValueProxy.Text = "Unknown";
+ ValueHosting.Text = "Unknown";
+ });
+ return;
+ }
+
+ // Set Variable labels
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ IpAddress.Content = _myIp;
+ ValueCityCountry.Text = city + " / " + country + " (" + countryCode + ")";
+ ValuePostal.Text = postal;
+ ValueTimezone.Text = timezone;
+ ValueLatitude.Text = latitude;
+ ValueLongitude.Text = longitude;
+ ValueIsp.Text = isp;
+ ValueAsn.Text = asn;
+ ValueMobile.Text = mobile;
+ ValueProxy.Text = proxy;
+ ValueHosting.Text = hosting;
+ });
+ }
+
+ private void ExportBtn_OnClick(object? sender, RoutedEventArgs e) => Task.Run(ExportTask);
+ private async Task ExportTask()
+ {
+ try
+ {
+ await Dispatcher.UIThread.InvokeAsync(async () =>
+ {
+ var exportString = $@"Report created at {DateTime.Now} for IP {IpAddress.Content}
+
+City / Country: {ValueCityCountry.Text}
+Postal: {ValuePostal.Text}
+Timezone: {ValueTimezone.Text}
+Latitude: {ValueLatitude.Text}
+Longitude: {ValueLongitude.Text}
+ISP or Organization: {ValueIsp.Text}
+ASN: {ValueAsn.Text}
+Is Mobile: {ValueMobile.Text}
+Is Proxy: {ValueProxy.Text}
+Is Hosting: {ValueHosting.Text}
+";
+ var options = new FilePickerSaveOptions
+ {
+ Title = "Export CheckIP Fetch Report",
+ ShowOverwritePrompt = true,
+ DefaultExtension = "txt",
+ FileTypeChoices = new FilePickerFileType[]
+ {
+ new("Text File (*.txt)") { Patterns = new[] { "txt" } }
+ }
+ };
+
+ var selectedFile = await Main.Instance.StorageProvider.SaveFilePickerAsync(options);
+ if (selectedFile.Path != null)
+ {
+ var path = selectedFile.Path;
+ File.WriteAllTextAsync(path.LocalPath, exportString);
+ }
+ });
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.ToString());
+ }
+
+ }
+ }
+}
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Program.cs b/CheckIP.Avalonia/CheckIP.Avalonia/Program.cs
new file mode 100644
index 0000000..5ff1961
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Program.cs
@@ -0,0 +1,21 @@
+using Avalonia;
+using System;
+
+namespace CheckIP
+{
+ 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()
+ .UsePlatformDetect()
+ .LogToTrace();
+ }
+}
\ No newline at end of file
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/Roots.xml b/CheckIP.Avalonia/CheckIP.Avalonia/Roots.xml
new file mode 100644
index 0000000..5e1cdc7
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/Roots.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/CheckIP.Avalonia/CheckIP.Avalonia/app.manifest b/CheckIP.Avalonia/CheckIP.Avalonia/app.manifest
new file mode 100644
index 0000000..e0ce8d0
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.Avalonia/app.manifest
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CheckIP.Avalonia/CheckIP.sln b/CheckIP.Avalonia/CheckIP.sln
new file mode 100644
index 0000000..783a408
--- /dev/null
+++ b/CheckIP.Avalonia/CheckIP.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33424.131
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CheckIP", "CheckIP.Avalonia\CheckIP.csproj", "{57F17352-350D-4782-A1E4-2BE2058A6FC1}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {57F17352-350D-4782-A1E4-2BE2058A6FC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {57F17352-350D-4782-A1E4-2BE2058A6FC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {57F17352-350D-4782-A1E4-2BE2058A6FC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {57F17352-350D-4782-A1E4-2BE2058A6FC1}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {DC062FDC-5E50-44F3-AD32-429F8BAF58B6}
+ EndGlobalSection
+EndGlobal
diff --git a/CheckIP.Avalonia/macOS.Sign/AppExecutable.entitlements b/CheckIP.Avalonia/macOS.Sign/AppExecutable.entitlements
new file mode 100644
index 0000000..4c24684
--- /dev/null
+++ b/CheckIP.Avalonia/macOS.Sign/AppExecutable.entitlements
@@ -0,0 +1,24 @@
+
+
+
+
+ com.apple.security.cs.allow-jit
+
+ com.apple.security.cs.allow-unsigned-executable-memory
+
+ com.apple.security.cs.disable-library-validation
+
+ com.apple.security.cs.allow-dyld-environment-variables
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.temporary-exception.mach-lookup.global-name
+
+ com.apple.coreservices.launchservicesd
+
+ com.apple.security.network.client
+
+ com.apple.security.files.user-selected.read-write
+
+
+
\ No newline at end of file
diff --git a/CheckIP.Avalonia/macOS.Sign/CheckIP.entitlements b/CheckIP.Avalonia/macOS.Sign/CheckIP.entitlements
new file mode 100644
index 0000000..384b033
--- /dev/null
+++ b/CheckIP.Avalonia/macOS.Sign/CheckIP.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.cs.allow-jit
+
+ com.apple.security.automation.apple-events
+
+
+
\ No newline at end of file
diff --git a/CheckIP.Avalonia/macOS.Sign/CheckIP.provisionprofile b/CheckIP.Avalonia/macOS.Sign/CheckIP.provisionprofile
new file mode 100644
index 0000000..1c1e6ad
Binary files /dev/null and b/CheckIP.Avalonia/macOS.Sign/CheckIP.provisionprofile differ
diff --git a/CheckIP.Avalonia/macOS.Sign/Helper.entitlements b/CheckIP.Avalonia/macOS.Sign/Helper.entitlements
new file mode 100644
index 0000000..244797d
--- /dev/null
+++ b/CheckIP.Avalonia/macOS.Sign/Helper.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.inherit
+
+
+
\ No newline at end of file
diff --git a/CheckIP.Avalonia/macOS.Sign/Info.plist b/CheckIP.Avalonia/macOS.Sign/Info.plist
new file mode 100644
index 0000000..cb30728
--- /dev/null
+++ b/CheckIP.Avalonia/macOS.Sign/Info.plist
@@ -0,0 +1,28 @@
+
+
+
+
+ CFBundleName
+ CheckIP
+ CFBundleDisplayName
+ CheckIP
+ CFBundleIdentifier
+ dev.valnoxy.checkip
+ CFBundleVersion
+ 1.0.0-preview1
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleExecutable
+ CheckIP
+ CFBundleIconFile
+ CheckIP.icns
+ CFBundleShortVersionString
+ 1.0.0-preview1
+ NSPrincipalClass
+ NSApplication
+ NSHighResolutionCapable
+
+
+
\ No newline at end of file
diff --git a/CheckIP.Avalonia/macOS.Sign/build-app.sh b/CheckIP.Avalonia/macOS.Sign/build-app.sh
new file mode 100755
index 0000000..e40be6e
--- /dev/null
+++ b/CheckIP.Avalonia/macOS.Sign/build-app.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+echo "[INFO] Building app file (arm64 - Silicon)"
+dotnet msbuild ../CheckIP.sln -t:BundleApp -p:RuntimeIdentifier=osx-arm64 -p:UseAppHost=true -p:Configuration=Release
+
+echo "[INFO] Building app file (x64 - Intel)"
+dotnet msbuild ../CheckIP.sln -t:BundleApp -p:RuntimeIdentifier=osx-x64 -p:UseAppHost=true -p:Configuration=Release
\ No newline at end of file
diff --git a/CheckIP.Avalonia/macOS.Sign/copy-app.sh b/CheckIP.Avalonia/macOS.Sign/copy-app.sh
new file mode 100755
index 0000000..6c2ba22
--- /dev/null
+++ b/CheckIP.Avalonia/macOS.Sign/copy-app.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+APP_NAME_ARM64="../CheckIP.Avalonia/bin/Release/net6.0/osx-arm64/publish/CheckIP.app"
+APP_NAME_X64="../CheckIP.Avalonia/bin/Release/net6.0/osx-x64/publish/CheckIP.app"
+OUTPUT="../Output"
+
+echo "[INFO] Copying app file (arm64 - Silicon)"
+cp -R $APP_NAME_ARM64 $OUTPUT/CheckIP-arm64.app
+
+echo "[INFO] Copying app file (x64 - Intel)"
+cp -R $APP_NAME_X64 $OUTPUT/CheckIP-x64.app
\ No newline at end of file
diff --git a/CheckIP.Avalonia/macOS.Sign/release-build.sh b/CheckIP.Avalonia/macOS.Sign/release-build.sh
new file mode 100755
index 0000000..d8be163
--- /dev/null
+++ b/CheckIP.Avalonia/macOS.Sign/release-build.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+APP_PATH_ARM64="../CheckIP.Avalonia/bin/Release/net6.0/osx-arm64/publish"
+APP_PATH_X64="../CheckIP.Avalonia/bin/Release/net6.0/osx-x64/publish"
+
+# cleanup folders
+echo "[INFO] Cleanup old builds ..."
+rm -rf "App/CheckIP-arm64.app/Contents/MacOS/"
+rm -rf "App/CheckIP-arm64.app/Contents/CodeResources"
+rm -rf "App/CheckIP-arm64.app/Contents/_CodeSignature"
+rm -rf "App/CheckIP-arm64.app/Contents/embedded.provisionprofile"
+mkdir -p "App/CheckIP-arm64.app/Contents/Frameworks/"
+mkdir -p "App/CheckIP-arm64.app/Contents/MacOS/"
+mkdir -p "App/CheckIP-arm64.app/Contents/Resources/"
+
+rm -rf "App/CheckIP-x64.app/Contents/MacOS/"
+rm -rf "App/CheckIP-x64.app/Contents/CodeResources"
+rm -rf "App/CheckIP-x64.app/Contents/_CodeSignature"
+rm -rf "App/CheckIP-x64.app/Contents/embedded.provisionprofile"
+mkdir -p "App/CheckIP-x64.app/Contents/Frameworks/"
+mkdir -p "App/CheckIP-x64.app/Contents/MacOS/"
+mkdir -p "App/CheckIP-x64.app/Contents/Resources/"
+
+# Build app
+echo "[INFO] Building app file (arm64 - Silicon)"
+dotnet publish ../CheckIP.sln -c Release -r osx-arm64 --self-contained true -p:PublishSingleFile=true
+
+echo "[INFO] Building app file (x64 - Intel)"
+dotnet publish ../CheckIP.sln -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true
+
+# Move app
+echo "[INFO] Moving app files (arm64 - Silicon)"
+cp -R -f $APP_PATH_ARM64/* "App/CheckIP-arm64.app/Contents/MacOS/"
+
+rm "App/CheckIP-arm64.app/Contents/MacOS/CheckIP.pdb"
+ln -s "App/CheckIP-arm64.app/Contents/MacOS/libAvaloniaNative.dylib" "App/CheckIP-arm64.app/Contents/Frameworks/libAvaloniaNative.dylib"
+ln -s "App/CheckIP-arm64.app/Contents/MacOS/libHarfBuzzSharp.dylib" "App/CheckIP-arm64.app/Contents/Frameworks/libHarfBuzzSharp.dylib"
+ln -s "App/CheckIP-arm64.app/Contents/MacOS/libSkiaSharp.dylib" "App/CheckIP-arm64.app/Contents/Frameworks/libSkiaSharp.dylib"
+mv "App/CheckIP-arm64.app/Contents/MacOS/CheckIP.icns" "App/CheckIP-arm64.app/Contents/Resources/CheckIP.icns"
+cp Info.plist "App/CheckIP-arm64.app/Contents/"
+
+echo "[INFO] Moving app files (x64 - Intel)"
+cp -R -f $APP_PATH_X64/* "App/CheckIP-x64.app/Contents/MacOS/"
+
+rm "App/CheckIP-x64.app/Contents/MacOS/CheckIP.pdb"
+ln -s "App/CheckIP-x64.app/Contents/MacOS/libAvaloniaNative.dylib" "App/CheckIP-x64.app/Contents/Frameworks/libAvaloniaNative.dylib"
+ln -s "App/CheckIP-x64.app/Contents/MacOS/libHarfBuzzSharp.dylib" "App/CheckIP-x64.app/Contents/Frameworks/libHarfBuzzSharp.dylib"
+ln -s "App/CheckIP-x64.app/Contents/MacOS/libSkiaSharp.dylib" "App/CheckIP-x64.app/Contents/Frameworks/libSkiaSharp.dylib"
+mv "App/CheckIP-x64.app/Contents/MacOS/CheckIP.icns" "App/CheckIP-x64.app/Contents/Resources/CheckIP.icns"
+cp Info.plist "App/CheckIP-x64.app/Contents/"
+
+# Sign app
+APP_ENTITLEMENTS="AppExecutable.entitlements"
+HELPER_ENTITLEMENTS="Helper.entitlements"
+APP_SIGNING_IDENTITY="Apple Distribution: Jonas Guenner (QHSR4A4M65)"
+INSTALLER_SIGNING_IDENTITY="3rd Party Mac Developer Installer: Jonas Guenner (QHSR4A4M65)"
+APP_NAME_ARM64="App/CheckIP-arm64.app"
+APP_NAME_X64="App/CheckIP-x64.app"
+
+echo "[INFO] Switch provisionprofile to AppStore"
+\cp -R -f CheckIP.provisionprofile "App/CheckIP-arm64.app/Contents/embedded.provisionprofile"
+\cp -R -f CheckIP.provisionprofile "App/CheckIP-x64.app/Contents/embedded.provisionprofile"
+
+#echo "[INFO] Fix libuv.dylib architectures"
+#lipo -remove i386 "App/CheckIP-arm64.app/Contents/Frameworks/libuv.dylib" "App/CheckIP-arm64.app/Contents/Frameworks/libuv.dylib"
+#lipo -remove i386 "App/CheckIP-x64.app/Contents/Frameworks/libuv.dylib" "App/CheckIP-x64.app/Contents/Frameworks/libuv.dylib"
+
+find "$APP_NAME_ARM64/Contents/Frameworks/"|while read fname; do
+ if [[ -f $fname ]]; then
+ echo "[INFO - ARM64] Signing $fname"
+ codesign --force --sign "$APP_SIGNING_IDENTITY" "$fname"
+ fi
+done
+
+find "$APP_NAME_X64/Contents/Frameworks/"|while read fname; do
+ if [[ -f $fname ]]; then
+ echo "[INFO - X64] Signing $fname"
+ codesign --force --sign "$APP_SIGNING_IDENTITY" "$fname"
+ fi
+done
+
+echo "[INFO] Signing app executables"
+codesign --force --entitlements "$HELPER_ENTITLEMENTS" --sign "$APP_SIGNING_IDENTITY" "App/CheckIP-arm64.app/Contents/MacOS/CheckIP"
+codesign --force --entitlements "$HELPER_ENTITLEMENTS" --sign "$APP_SIGNING_IDENTITY" "App/CheckIP-x64.app/Contents/MacOS/CheckIP"
+
+echo "[INFO] Signing app bundle"
+codesign --force --entitlements "$APP_ENTITLEMENTS" --sign "$APP_SIGNING_IDENTITY" "$APP_NAME_ARM64"
+codesign --force --entitlements "$APP_ENTITLEMENTS" --sign "$APP_SIGNING_IDENTITY" "$APP_NAME_X64"
+
+echo "[INFO] Creating CheckIP-arm64.pkg"
+productbuild --component App/CheckIP-arm64.app /Applications --sign "$INSTALLER_SIGNING_IDENTITY" CheckIP-arm64.pkg
+
+echo "[INFO] Creating CheckIP-x64.pkg"
+productbuild --component App/CheckIP-x64.app /Applications --sign "$INSTALLER_SIGNING_IDENTITY" CheckIP-x64.pkg
\ No newline at end of file
diff --git a/CheckIP.Avalonia/macOS.Sign/sign-app.sh b/CheckIP.Avalonia/macOS.Sign/sign-app.sh
new file mode 100755
index 0000000..aacc47d
--- /dev/null
+++ b/CheckIP.Avalonia/macOS.Sign/sign-app.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+APP_NAME_ARM64="../CheckIP.Avalonia/bin/Release/net6.0/osx-arm64/publish/CheckIP.app"
+APP_NAME_X64="../CheckIP.Avalonia/bin/Release/net6.0/osx-x64/publish/CheckIP.app"
+ENTITLEMENTS="CheckIP.entitlements"
+SIGNING_IDENTITY="Developer ID Application: Jonas Guenner (QHSR4A4M65)" # matches Keychain Access certificate name
+
+find "$APP_NAME_ARM64/Contents/MacOS/"|while read fname; do
+ if [[ -f $fname ]]; then
+ echo "[INFO - ARM64] Signing $fname"
+ codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" "$fname"
+ fi
+done
+
+find "$APP_NAME_X64/Contents/MacOS/"|while read fname; do
+ if [[ -f $fname ]]; then
+ echo "[INFO - X64] Signing $fname"
+ codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" "$fname"
+ fi
+done
+
+echo "[INFO] Signing app file (arm64 - Silicon)"
+codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" "$APP_NAME_ARM64"
+
+echo "[INFO] Signing app file (x64 - Intel)"
+codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" "$APP_NAME_X64"
\ No newline at end of file
diff --git a/CheckIP.Windows/CheckIP/CheckIP.csproj b/CheckIP.Windows/CheckIP/CheckIP.csproj
index b70f69b..b0e7d1c 100644
--- a/CheckIP.Windows/CheckIP/CheckIP.csproj
+++ b/CheckIP.Windows/CheckIP/CheckIP.csproj
@@ -13,6 +13,7 @@
2.2.1
AnyCPU;ARM32;ARM64;x64;x86
false
+ win-x86;win-x64
diff --git a/README.md b/README.md
index f6ab3d3..6e66c76 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@
[](https://github.com/valnoxy/checkip/tree/main/CheckIP.Mobile)
[](https://github.com/valnoxy/checkip/tree/main/CheckIP.Mobile)
+[](https://github.com/valnoxy/checkip/tree/main/CheckIP.MacOS)
[](https://github.com/valnoxy/checkip/tree/main/CheckIP.Windows)
[](/LICENSE)
@@ -12,6 +13,8 @@
WPF Version: 2.2.1
+ Avalonia (macOS) Version: 0.1.0-dev (WIP)
+
Xamarin Version: 2.1.0-alpha2
Report Bug