394 lines
15 KiB
C#
394 lines
15 KiB
C#
using System.Xml.Linq;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using netxml2kml.Data;
|
||
using netxml2kml.Models;
|
||
using Serilog;
|
||
|
||
namespace netxml2kml.Methods;
|
||
|
||
public static class CliOptionsHandlers
|
||
{
|
||
public static Task<int> UniversalHandler(FileInfo? inputFile,
|
||
FileInfo? outputFile, bool useDatabase, string? sqlQuery,
|
||
IEnumerable<FileInfo>? concatFiles, bool isVerbose)
|
||
{
|
||
Log.Information("Handler started with options: " +
|
||
"-i: {input}; -o {output}; -d {useDatabase}; " +
|
||
"-q: {sqlQuery}; -c: {concatFiles}; -v: {verbosityLevel}.",
|
||
inputFile!, outputFile!, useDatabase,
|
||
sqlQuery!, concatFiles!, isVerbose);
|
||
|
||
try
|
||
{
|
||
// Run some logic based on options combination
|
||
if (inputFile != null && outputFile != null)
|
||
{
|
||
var wirelessNetworks = Helpers.DeserializeXml(inputFile);
|
||
|
||
if (useDatabase)
|
||
{
|
||
AddWirelessNetworksToDatabase(wirelessNetworks);
|
||
}
|
||
|
||
if (sqlQuery != null)
|
||
{
|
||
FilterWirelessNetworksInMemory(ref wirelessNetworks,
|
||
sqlQuery);
|
||
}
|
||
|
||
var kmlString = GetKmlString(wirelessNetworks,
|
||
$"WiFi Map - {outputFile.Name}");
|
||
Helpers.WriteStringToFile(kmlString, outputFile);
|
||
}
|
||
else if (inputFile != null && outputFile == null && useDatabase)
|
||
{
|
||
var wirelessNetworks = Helpers.DeserializeXml(inputFile);
|
||
|
||
if (sqlQuery != null)
|
||
{
|
||
FilterWirelessNetworksInMemory(ref wirelessNetworks,
|
||
sqlQuery);
|
||
}
|
||
|
||
AddWirelessNetworksToDatabase(wirelessNetworks);
|
||
}
|
||
else if (inputFile == null && outputFile != null && useDatabase)
|
||
{
|
||
string kmlString;
|
||
|
||
if (sqlQuery != null)
|
||
{
|
||
kmlString = GetKmlString(
|
||
FilterWirelessNetworksFromDatabase(sqlQuery),
|
||
$"WiFi Map - {outputFile.Name}");
|
||
}
|
||
else
|
||
{
|
||
kmlString = GetKmlString(
|
||
FilterWirelessNetworksFromDatabase(
|
||
"SELECT * FROM WirelessNetworks"),
|
||
$"WiFi Map - {outputFile.Name}");
|
||
}
|
||
|
||
Helpers.WriteStringToFile(kmlString, outputFile);
|
||
}
|
||
else if (inputFile == null && outputFile == null && useDatabase &&
|
||
sqlQuery != null)
|
||
{
|
||
using var dbContext = new DatabaseContext();
|
||
Console.WriteLine(dbContext.Database.ExecuteSqlRaw(sqlQuery));
|
||
}
|
||
else if (concatFiles != null && outputFile != null)
|
||
{
|
||
var inputFiles =
|
||
concatFiles as FileInfo[] ?? concatFiles.ToArray();
|
||
var kmlString = ConcatKml(inputFiles);
|
||
Helpers.WriteStringToFile(kmlString, outputFile);
|
||
}
|
||
else
|
||
{
|
||
Log.Warning("Options combination is unsupported: " +
|
||
"-i: {input}; -o {output}; -d {useDatabase}; " +
|
||
"-q: {sqlQuery}; -c: {concatFiles}; -v: {verbosityLevel}.",
|
||
inputFile!, outputFile!, useDatabase,
|
||
sqlQuery!, concatFiles!, isVerbose);
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Log.Fatal(e, "Program ended unexpectedly. " +
|
||
"Run command with -v option and see logs in {logsFold}" +
|
||
"to troubleshoot the error.",
|
||
RuntimeStorage.LogsFolder);
|
||
return Task.FromResult(1);
|
||
}
|
||
finally
|
||
{
|
||
Log.CloseAndFlush();
|
||
}
|
||
|
||
Log.Information("Options handling completed successfully.");
|
||
return Task.FromResult(0);
|
||
}
|
||
|
||
private static string GetKmlString(IEnumerable<WirelessNetwork> wirelessNetworks,
|
||
string name = "WiFi Map",
|
||
string description = $"Autogenerated by a tool." +
|
||
$"\nhttps://github.com/cuqmbr/netxml2kml")
|
||
{
|
||
Log.Information("Generating kml...");
|
||
|
||
var kmlTree = new XDocument();
|
||
|
||
var kml = new XElement("kml");
|
||
var document = new XElement("Document",
|
||
new XElement("name", $"{name}"),
|
||
new XElement("description", $"{description}"));
|
||
|
||
var wpa3Folder = new XElement("Folder",
|
||
new XElement("name", "WPA3"));
|
||
var wpa2Folder = new XElement("Folder",
|
||
new XElement("name", "WPA2"));
|
||
var wpaFolder = new XElement("Folder",
|
||
new XElement("name", "WPA"));
|
||
var wepFolder = new XElement("Folder",
|
||
new XElement("name", "WEP"));
|
||
var opnFolder = new XElement("Folder",
|
||
new XElement("name", "OPN"));
|
||
var unknownFolder = new XElement("Folder",
|
||
new XElement("name", "UNKNOWN"));
|
||
|
||
foreach (var wn in wirelessNetworks)
|
||
{
|
||
if (wn.Encryption == null)
|
||
{
|
||
AddWirelessNetworkPlacemark(unknownFolder, wn);
|
||
}
|
||
else if (wn.Encryption.Contains("None"))
|
||
{
|
||
AddWirelessNetworkPlacemark(opnFolder, wn);
|
||
}
|
||
else if (wn.Encryption.Contains("RC4"))
|
||
{
|
||
AddWirelessNetworkPlacemark(wepFolder, wn);
|
||
}
|
||
else if (wn.Encryption.Contains("TKIP"))
|
||
{
|
||
AddWirelessNetworkPlacemark(wpaFolder, wn);
|
||
}
|
||
else if (wn.Encryption.Contains("AES") || wn.Encryption.Contains("PSK"))
|
||
{
|
||
AddWirelessNetworkPlacemark(wpa2Folder, wn);
|
||
}
|
||
else if (wn.Encryption.Contains("SAE"))
|
||
{
|
||
AddWirelessNetworkPlacemark(wpa3Folder, wn);
|
||
}
|
||
else
|
||
{
|
||
AddWirelessNetworkPlacemark(unknownFolder, wn);
|
||
}
|
||
}
|
||
|
||
document.Add(wpa3Folder);
|
||
document.Add(wpa2Folder);
|
||
document.Add(wpaFolder);
|
||
document.Add(wepFolder);
|
||
document.Add(opnFolder);
|
||
document.Add(unknownFolder);
|
||
kml.Add(document);
|
||
kmlTree.Add(kml);
|
||
|
||
Log.Information("Kml generated.");
|
||
|
||
return kmlTree.ToString();
|
||
|
||
void AddWirelessNetworkPlacemark(XElement parent, WirelessNetwork wn)
|
||
{
|
||
parent.Add(new XElement("Placemark",
|
||
new XElement("name", $"{wn.Essid}"),
|
||
new XElement("description",
|
||
$"Name: {wn.Essid}" +
|
||
$"\n\nManufacturer: {wn.Manufacturer}" +
|
||
$"\n\nBSSID: {wn.Bssid}" +
|
||
$"\n\nEncryption: {wn.Encryption}" +
|
||
$"\n\nUpdated: {wn.LastUpdateDate}"),
|
||
new XElement("Point",
|
||
new XElement("coordinates",
|
||
$"{wn.MaxLongitude},{wn.MaxLatitude},{wn.MaxAltitude}"))));
|
||
}
|
||
}
|
||
|
||
private static void AddWirelessNetworksToDatabase(IEnumerable<WirelessNetwork> wirelessNetworks)
|
||
{
|
||
Log.Information("Adding wireless networks to the database...");
|
||
|
||
using var dbContext = new DatabaseContext();
|
||
|
||
foreach (var wirelessNetwork in wirelessNetworks)
|
||
{
|
||
// If wireless network has wireless clients – add all clients to
|
||
// the database or update their LastUpdateDate
|
||
if (wirelessNetwork.WirelessConnections != null)
|
||
{
|
||
foreach (var wirelessConnection in wirelessNetwork.WirelessConnections)
|
||
{
|
||
var client = wirelessConnection.WirelessClient;
|
||
client.WirelessConnections = null!;
|
||
|
||
// Add new client to the DB if it is not present
|
||
if (!dbContext.WirelessClients.Any(wc =>
|
||
wc.Mac == client.Mac))
|
||
{
|
||
dbContext.WirelessClients.Add(client);
|
||
}
|
||
// Update LastUpdateDate if the client is present in the DB
|
||
else if (dbContext.WirelessClients.Any(wc =>
|
||
wc.Mac == client.Mac))
|
||
{
|
||
var dbClient = dbContext.WirelessClients
|
||
.First(wc => wc.Mac == client.Mac);
|
||
|
||
if (dbClient.LastUpdateDate < client.FirstSeenDate)
|
||
{
|
||
dbClient.LastUpdateDate = client.FirstSeenDate;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// If wireless network has wireless clients – add a wireless
|
||
// connections to the database or update their LastUpdateDate
|
||
if (wirelessNetwork.WirelessConnections != null)
|
||
{
|
||
foreach (var wirelessConnection in wirelessNetwork.WirelessConnections)
|
||
{
|
||
var client = wirelessConnection.WirelessClient;
|
||
|
||
// Add new connection to the DB if it is not present
|
||
if (!dbContext.WirelessConnections.Any(wc =>
|
||
wc.WirelessClientMac == client.Mac &&
|
||
wc.WirelessNetworkBssid == wirelessNetwork.Bssid))
|
||
{
|
||
dbContext.WirelessConnections.Add(new WirelessConnection
|
||
{
|
||
WirelessClientMac = client.Mac,
|
||
WirelessNetworkBssid = wirelessNetwork.Bssid,
|
||
FirstSeenDate = client.FirstSeenDate,
|
||
LastUpdateDate = client.LastUpdateDate
|
||
});
|
||
}
|
||
// Update LastUpdateDate if the connection is present in the DB
|
||
else if (dbContext.WirelessConnections.Any(wc =>
|
||
wc.WirelessClientMac == client.Mac &&
|
||
wc.WirelessNetworkBssid == wirelessNetwork.Bssid))
|
||
{
|
||
var dbConnection = dbContext.WirelessConnections.First(
|
||
wc => wc.WirelessClientMac == client.Mac &&
|
||
wc.WirelessNetworkBssid == wirelessNetwork.Bssid);
|
||
var connectedClient = wirelessNetwork
|
||
.WirelessConnections
|
||
.First(wc => wc.WirelessClient.Mac == client.Mac)
|
||
.WirelessClient;
|
||
|
||
if (dbConnection.LastUpdateDate < connectedClient.FirstSeenDate)
|
||
{
|
||
dbConnection.LastUpdateDate =
|
||
connectedClient.FirstSeenDate;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Set wireless connections to null since we manually added
|
||
// connections to the database context
|
||
wirelessNetwork.WirelessConnections = null;
|
||
|
||
// Add new network to the DB if it is not present
|
||
if (!dbContext.WirelessNetworks.Any(wn =>
|
||
wn.Bssid == wirelessNetwork.Bssid))
|
||
{
|
||
dbContext.Add(wirelessNetwork);
|
||
}
|
||
// Update LastUpdateDate & MaxSignalDmb if
|
||
// the network is present in the DB
|
||
else if (dbContext.WirelessNetworks.Any(wn =>
|
||
wn.Bssid == wirelessNetwork.Bssid))
|
||
{
|
||
var dbNetwork = dbContext.WirelessNetworks.First(wn =>
|
||
wn.Bssid == wirelessNetwork.Bssid);
|
||
|
||
if (dbNetwork.MaxSignalDbm < wirelessNetwork.MaxSignalDbm)
|
||
{
|
||
dbNetwork.MaxLatitude = wirelessNetwork.MaxLatitude;
|
||
dbNetwork.MaxLongitude = wirelessNetwork.MaxLongitude;
|
||
dbNetwork.MaxAltitude = wirelessNetwork.MaxAltitude;
|
||
dbNetwork.MaxSignalDbm = wirelessNetwork.MaxSignalDbm;
|
||
}
|
||
|
||
if (dbNetwork.LastUpdateDate < wirelessNetwork.FirstSeenDate)
|
||
{
|
||
dbNetwork.LastUpdateDate = wirelessNetwork.FirstSeenDate;
|
||
}
|
||
}
|
||
}
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
Log.Information("Wireless networks added successfully.");
|
||
}
|
||
|
||
private static void FilterWirelessNetworksInMemory(
|
||
ref WirelessNetwork[] wirelessNetworks, string sqlQuery)
|
||
{
|
||
Log.Information("Filtering wireless network using {query}...",
|
||
sqlQuery);
|
||
|
||
using var dbContext = new DatabaseContext("InMemoryFiltering.sqlite3.db");
|
||
|
||
dbContext.WirelessNetworks.AddRange(wirelessNetworks);
|
||
dbContext.SaveChanges();
|
||
wirelessNetworks = dbContext.WirelessNetworks.FromSqlRaw(sqlQuery).ToArray();
|
||
|
||
dbContext.Database.EnsureDeleted();
|
||
|
||
Log.Information("Networks are filtered.");
|
||
}
|
||
|
||
private static WirelessNetwork[] FilterWirelessNetworksFromDatabase(string sqlQuery)
|
||
{
|
||
Log.Information("Filtering wireless network using {query}...",
|
||
sqlQuery);
|
||
|
||
using var dbContext = new DatabaseContext();
|
||
var wirelessNetworks = dbContext.WirelessNetworks.FromSqlRaw(sqlQuery);
|
||
|
||
Log.Information("Networks are filtered.");
|
||
|
||
return wirelessNetworks.ToArray();
|
||
}
|
||
|
||
private static string ConcatKml(IEnumerable<FileInfo> inputFiles)
|
||
{
|
||
Log.Information("Concatenating kml...");
|
||
|
||
var inFs = inputFiles.ToArray();
|
||
var result = XDocument.Load(inFs[0].FullName);
|
||
|
||
result.Root!.Element("Document")!.Element("name")!.Value =
|
||
"WiFi Map - Concatenated";
|
||
|
||
var folders = result.Root?.Element("Document")?.Elements("Folder")
|
||
.ToArray();
|
||
var wpa3Folder = folders?[0];
|
||
var wpa2Folder = folders?[1];
|
||
var wpaFolder = folders?[2];
|
||
var wepFolder = folders?[3];
|
||
var opnFolder = folders?[4];
|
||
var unknownFolder = folders?[5];
|
||
|
||
foreach (var inF in inFs[1..])
|
||
{
|
||
var inFDoc = XDocument.Load(inF.FullName);
|
||
var inFolders = inFDoc.Root?.Element("Document")?.Elements("Folder")
|
||
.ToArray();
|
||
|
||
inFolders?[0].Elements("Placemark").ToList()
|
||
.ForEach(p => wpa3Folder?.Add(p));
|
||
inFolders?[1].Elements("Placemark").ToList()
|
||
.ForEach(p => wpa2Folder?.Add(p));
|
||
inFolders?[2].Elements("Placemark").ToList()
|
||
.ForEach(p => wpaFolder?.Add(p));
|
||
inFolders?[3].Elements("Placemark").ToList()
|
||
.ForEach(p => wepFolder?.Add(p));
|
||
inFolders?[4].Elements("Placemark").ToList()
|
||
.ForEach(p => opnFolder?.Add(p));
|
||
inFolders?[5].Elements("Placemark").ToList()
|
||
.ForEach(p => unknownFolder?.Add(p));
|
||
}
|
||
|
||
Log.Information("Concatenating successfully.");
|
||
|
||
return result.ToString();
|
||
}
|
||
} |