Skip to content

Commit 2c6b11f

Browse files
authored
Merge pull request CactuseSecurity#3113 from SolidProgramming/issue_3024
Merge: Modelling csv import improvements
2 parents 322a553 + c1dc68e commit 2c6b11f

File tree

9 files changed

+356
-294
lines changed

9 files changed

+356
-294
lines changed

roles/database/files/sql/idempotent/fworch-texts.sql

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,8 +1607,12 @@ INSERT INTO txt VALUES ('generate_name', 'German', 'Name generieren');
16071607
INSERT INTO txt VALUES ('generate_name', 'English', 'Generate Name');
16081608
INSERT INTO txt VALUES ('change_source', 'German', 'Änderungsquelle');
16091609
INSERT INTO txt VALUES ('change_source', 'English', 'Change Source');
1610-
INSERT INTO txt VALUES ('tableofcontent', 'German', 'Inhaltsverzeichnis');
1611-
INSERT INTO txt VALUES ('tableofcontent', 'English', 'Table of content');
1610+
INSERT INTO txt VALUES ('tableofcontent', 'German', 'Inhaltsverzeichnis');
1611+
INSERT INTO txt VALUES ('tableofcontent', 'English', 'Table of content');
1612+
INSERT INTO txt VALUES ('entrydata', 'German', 'Dateneintrag');
1613+
INSERT INTO txt VALUES ('entrydata', 'English', 'Data entry');
1614+
INSERT INTO txt VALUES ('error_message', 'German', 'Fehlermeldung');
1615+
INSERT INTO txt VALUES ('error_message', 'English', 'Error message');
16121616

16131617
-- compliance
16141618
INSERT INTO txt VALUES ('compliance', 'German', 'Compliance');
@@ -2365,6 +2369,10 @@ INSERT INTO txt VALUES ('app_zone_pattern', 'German', 'Muster App Zone');
23652369
INSERT INTO txt VALUES ('app_zone_pattern', 'English', 'App Zone Pattern');
23662370
INSERT INTO txt VALUES ('app_zone_creation', 'German', 'App Zonen Objekte erstellen');
23672371
INSERT INTO txt VALUES ('app_zone_creation', 'English', 'Create App Zone Objects');
2372+
INSERT INTO txt VALUES ('appserver_import', 'German', 'App server import');
2373+
INSERT INTO txt VALUES ('appserver_import', 'English', 'App server import');
2374+
INSERT INTO txt VALUES ('select_file', 'German', 'Datei auswählen');
2375+
INSERT INTO txt VALUES ('select_file', 'English', 'Select file');
23682376

23692377
-- monitoring
23702378
INSERT INTO txt VALUES ('open_alerts', 'German', 'Offene Alarme');
@@ -3100,6 +3108,10 @@ INSERT INTO txt VALUES ('E5415', 'German', 'Passwort muss mindestens ein Sonder
31003108
INSERT INTO txt VALUES ('E5415', 'English', 'Password must contain at least one special character (!?(){}=~$%&#*-+.,_)');
31013109
INSERT INTO txt VALUES ('E5421', 'German', 'Schlüssel nicht gefunden oder Wert nicht konvertierbar: Wert wird gesetzt auf: ');
31023110
INSERT INTO txt VALUES ('E5421', 'English', 'Key not found or could not convert value to int: taking value: ');
3111+
INSERT INTO txt VALUES ('E5422', 'German', 'Eintrag enthält nicht alle erforderlichen Spalten');
3112+
INSERT INTO txt VALUES ('E5422', 'English', 'Entry does not contain all required columns');
3113+
INSERT INTO txt VALUES ('E5423', 'German', 'IP-Adresse/IP-Bereich ist fehlerhaft');
3114+
INSERT INTO txt VALUES ('E5423', 'English', 'IP Address/IP Range malformed');
31033115

31043116
INSERT INTO txt VALUES ('E6001', 'German', 'Der Re-Login war nicht erfolgreich. Haben Sie ein falsches Passwort eingegeben? Schauen Sie für Details bitte in die Logs.');
31053117
INSERT INTO txt VALUES ('E6001', 'English', 'Re-login failed. Did you enter a wrong password? See log for details.');

roles/lib/files/FWO.Basics/IpOperations.cs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Net.Sockets;
22
using System.Net;
33
using NetTools;
4+
using System;
45

56
namespace FWO.Basics
67
{
@@ -39,6 +40,111 @@ public static (string, string) SplitIpToRange(string ipString)
3940
return (ipStart, ipEnd);
4041
}
4142

43+
public static bool TryParseIPStringToRange(this string ipString, out (string Start, string End) ipRange, bool strictv4Parse = false)
44+
{
45+
ipRange = default;
46+
47+
try
48+
{
49+
(string ipStart, string ipEnd) = SplitIpToRange(ipString);
50+
51+
bool ipStartOK = IPAddress.TryParse(ipStart, out IPAddress? ipAdressStart);
52+
bool ipEndOK = IPAddress.TryParse(ipEnd, out IPAddress? ipAdressEnd);
53+
54+
if(ipAdressStart is null || ipAdressEnd is null)
55+
{
56+
return false;
57+
}
58+
59+
if(strictv4Parse && ipAdressStart?.AddressFamily == AddressFamily.InterNetwork && ipAdressEnd?.AddressFamily == AddressFamily.InterNetwork)
60+
{
61+
if(!IsValidIPv4(ipStart) || !IsValidIPv4(ipEnd))
62+
{
63+
return false;
64+
}
65+
}
66+
67+
if(!ipStartOK || !ipEndOK)
68+
{
69+
return false;
70+
}
71+
72+
if(!IPAddress.TryParse(ipStart, out _) || !IPAddress.TryParse(ipEnd, out _))
73+
{
74+
return false;
75+
}
76+
77+
ipRange.Start = ipStart;
78+
ipRange.End = ipEnd;
79+
80+
return true;
81+
}
82+
catch(Exception)
83+
{
84+
return false;
85+
}
86+
}
87+
88+
public static bool TryParseIPString<T>(this string ipString, out T? ipResult, bool strictv4Parse = false)
89+
{
90+
ipResult = default;
91+
92+
try
93+
{
94+
(string ipStart, string ipEnd) = SplitIpToRange(ipString);
95+
96+
bool ipStartOK = IPAddress.TryParse(ipStart, out IPAddress? ipAdressStart);
97+
bool ipEndOK = IPAddress.TryParse(ipEnd, out IPAddress? ipAdressEnd);
98+
99+
if(ipAdressStart is null || ipAdressEnd is null)
100+
{
101+
return false;
102+
}
103+
104+
if(strictv4Parse && ipAdressStart?.AddressFamily == AddressFamily.InterNetwork && ipAdressEnd?.AddressFamily == AddressFamily.InterNetwork)
105+
{
106+
if(!IsValidIPv4(ipStart) || !IsValidIPv4(ipEnd))
107+
{
108+
return false;
109+
}
110+
}
111+
112+
if(!ipStartOK || !ipEndOK)
113+
{
114+
return false;
115+
}
116+
117+
if(typeof(T) == typeof((string, string)))
118+
{
119+
ipResult = (T)Convert.ChangeType((ipAdressStart.ToString(), ipAdressEnd.ToString()), typeof(T));
120+
return true;
121+
}
122+
else if(typeof(T) == typeof(IPAddressRange) && IPAddressRange.TryParse(ipString, out IPAddressRange ipRange))
123+
{
124+
ipResult = (T)Convert.ChangeType(ipRange, typeof(T));
125+
return true;
126+
}else if(typeof(T) == typeof((IPAddress, IPAddress)))
127+
{
128+
Tuple<IPAddress, IPAddress>? ipTuple = new(ipAdressStart, ipAdressEnd);
129+
ipResult = (T)Convert.ChangeType(ipTuple, typeof(T));
130+
return true;
131+
}
132+
133+
return false;
134+
}
135+
catch(Exception)
136+
{
137+
return false;
138+
}
139+
}
140+
141+
private static bool IsValidIPv4(string ipAddress)
142+
{
143+
byte[] addBytes = [.. ipAddress.Split('.').Where(_ => byte.Parse(_) <= 255 && byte.Parse(_) >= 0).Select(byte.Parse)];
144+
145+
return addBytes.Length == 4;
146+
}
147+
42148
public static string GetObjectType(string ip1, string ip2)
43149
{
44150
ip1 = ip1.StripOffUnnecessaryNetmask();

roles/ui/files/FWO.UI/Data/CSVAppServerImportModel.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using FWO.Basics;
1+
using FWO.Basics;
22
using FWO.Data.Modelling;
33

44
namespace FWO.Ui.Data
@@ -16,6 +16,11 @@ public CSVAppServerImportModel (string ipString)
1616
(AppIPRangeStart, AppIPRangeEnd) = IpOperations.SplitIpToRange(ipString);
1717
}
1818

19+
public CSVAppServerImportModel()
20+
{
21+
22+
}
23+
1924
public ModellingAppServer ToModellingAppServer()
2025
{
2126
return new ModellingAppServer()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace FWO.Ui.Data
2+
{
3+
/// <summary>
4+
/// Defines a model for errors that occured on csv file upload
5+
/// </summary>
6+
public class CSVFileUploadErrorModel : ErrorBaseModel
7+
{
8+
public CSVFileUploadErrorModel() : base()
9+
{
10+
}
11+
12+
/// <summary>
13+
/// Additional Data/Info
14+
/// </summary>
15+
public string? EntryData { get; set; }
16+
}
17+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace FWO.Ui.Data
2+
{
3+
public class ErrorBaseModel()
4+
{
5+
/// <summary>
6+
/// The error message containing infos abour what went wrong
7+
/// </summary>
8+
public string? Message { get; set; }
9+
10+
/// <summary>
11+
/// Additional info on errors at system level
12+
/// </summary>
13+
public Exception? InternalException { get; set; }
14+
15+
/// <summary>
16+
/// Identifier for severity typing
17+
/// </summary>
18+
public MessageType MessageType { get; set; }
19+
}
20+
}

roles/ui/files/FWO.UI/Pages/Settings/SettingsModelling.razor

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
@using System.Text.Json
1+
@using System.Text.Json
2+
@using FWO.Ui.Data
23
@using FWO.Ui.Pages.NetworkModelling
34

45
@page "/settings/modelling"
@@ -15,11 +16,11 @@
1516
@(userConfig.GetText("U5322"))
1617
<hr />
1718

18-
@if (configData != null && initComplete)
19+
@if(configData != null && initComplete)
1920
{
2021
<form onsubmit="return false">
2122
<button type="button" class="btn btn-sm btn-dark ms-5" data-toggle="tooltip" title="@(userConfig.PureLine("H5602"))"
22-
@onclick="PredefServices">
23+
@onclick="PredefServices">
2324
@(userConfig.GetText("predef_services"))
2425
</button>
2526
<hr />
@@ -82,7 +83,7 @@
8283
<div class="form-group row mt-4" data-toggle="tooltip" title="@(userConfig.PureLine("H9055"))">
8384
<label class="col-form-label col-sm-4">@userConfig.GetText("import_app_server"):</label>
8485
<div class="row col-sm-6">
85-
<CSVFileUpload AuthorizedRoles="@Roles.Admin" OnAddAppServerError="OnAddAppServerError" OnAddAppServerWarning="OnAddAppServerWarning" OnImportSuccess="OnAppServerImportSuccess"></CSVFileUpload>
86+
<FileUpload SupportedFileFormats=".csv" AuthorizedRoles="@Roles.Admin" OnImportSuccess="OnAppServerImportSuccess" OnAddAppServerError="OnAddAppServerError" TImportResult="CSVFileUploadErrorModel" OnAfterImportResults="OnAfterImportResults"></FileUpload>
8687
</div>
8788
</div>
8889
<hr />
@@ -371,6 +372,37 @@ else
371372
}
372373
<PredefServices @bind-Display="predefServices" />
373374
<SearchNwObject @bind-Display="searchArea" ObjectList="pureAreaList" Add="AddArea" CommonAreaMode="true" />
375+
<PopUp Title="@(userConfig.GetText("appserver_import"))" Show="@ShowCSVImportPopUp" Size=PopupSize.Large OnClose="() => ShowCSVImportPopUp = false">
376+
<Body>
377+
@if(CSVImportSuccess is not null && CSVImportSuccess.Count > 0)
378+
{
379+
<div class="mt-3">
380+
<Collapse StartToggled="true" Style="success" Title="@(userConfig.GetText("success"))">
381+
<Table PageSize="0" TableClass="table table-bordered table-sm th-bg-secondary table-responsive overflow-auto sticky-header" TableItem="string" Items="CSVImportSuccess">
382+
<Column TableItem="string" Title="@(userConfig.GetText("entrydata"))" Type="typeof(string)" Field="@(_ => new string(_))" Sortable="true" Filterable="true" />
383+
</Table>
384+
</Collapse>
385+
</div>
386+
}
387+
@if(CSVImportErrors is not null && CSVImportErrors.Count > 0)
388+
{
389+
<div class="mt-1">
390+
<Collapse StartToggled="false" Style="danger" Title="@(userConfig.GetText("errors"))">
391+
<Table PageSize="0" TableClass="table table-bordered table-sm th-bg-secondary table-responsive overflow-auto sticky-header" TableItem="CSVFileUploadErrorModel" Items="CSVImportErrors">
392+
<Column TableItem="CSVFileUploadErrorModel" Title="@(userConfig.GetText("entrydata"))" Field="@(_ => _.EntryData)" Sortable="true" Filterable="true" />
393+
<Column TableItem="CSVFileUploadErrorModel" Title="@(userConfig.GetText("error_message"))" Field="@(_ => _.Message)" Sortable="true" Filterable="true" />
394+
<Column TableItem="CSVFileUploadErrorModel" Title="@(userConfig.GetText("type"))" Field="@(_ => _.MessageType)" Sortable="true" />
395+
</Table>
396+
</Collapse>
397+
</div>
398+
}
399+
</Body>
400+
<Footer>
401+
<div class="btn-group">
402+
<button type="button" class="btn btn-sm btn-primary" @onclick="() => ShowCSVImportPopUp = false">@(userConfig.GetText("ok"))</button>
403+
</div>
404+
</Footer>
405+
</PopUp>
374406

375407
@code
376408
{
@@ -416,23 +448,22 @@ else
416448
private List<UiLdapConnection> connectedLdaps = new List<UiLdapConnection>();
417449
private UiLdapConnection selectedLdap = new();
418450
private bool initComplete = false;
419-
451+
private bool ShowCSVImportPopUp { get; set; }
452+
private List<CSVFileUploadErrorModel>? CSVImportErrors;
453+
private List<string>? CSVImportSuccess;
420454

421455
private void OnAddAppServerError((Exception Exception, string Message) error)
422456
{
423457
DisplayMessageInUi(error.Exception, userConfig.GetText("add_app_server"), error.Message, false);
424458
}
425459

426-
private void OnAddAppServerWarning(string errorMessage)
460+
private void OnAfterImportResults((List<string>? Success, List<CSVFileUploadErrorModel>? Errors) importResult)
427461
{
428-
DisplayMessageInUi(null, userConfig.GetText("add_app_server"), errorMessage, true);
429-
}
462+
CSVImportSuccess = importResult.Success;
463+
CSVImportErrors = importResult.Errors;
430464

431-
private void OnAddAppServerWarning(Exception ex)
432-
{
433-
DisplayMessageInUi(ex, userConfig.GetText("add_app_server"), ex.Message, false);
465+
ShowCSVImportPopUp = true;
434466
}
435-
436467
private void OnAppServerImportSuccess()
437468
{
438469
DisplayMessageInUi(null, userConfig.GetText("import_app_server"), userConfig.GetText("importAppServerDataSuccess"), false);

0 commit comments

Comments
 (0)