29
29
using Manatee . Json . Serialization ;
30
30
using Manatee . Json . Schema ;
31
31
using System . Text . Json ;
32
+ using System . Text . RegularExpressions ;
32
33
33
34
namespace Enter_The_Matrix . Controllers
34
35
{
@@ -101,7 +102,7 @@ public async Task<IActionResult> DeleteAssessment(string assessmentId)
101
102
Assessments assessment = _assessmentsService . GetByIdAsync ( assessmentId ) . Result ;
102
103
103
104
// Delete the threat tree associated with the assessment
104
- await _treeService . DeleteAsync ( assessment . ThreatTreeId ) ;
105
+ if ( assessment . ThreatTreeId != null && assessment . ThreatTreeId != "" ) { await _treeService . DeleteAsync ( assessment . ThreatTreeId ) ; }
105
106
106
107
// Clean out scenarios and events
107
108
foreach ( var scenarioId in assessment . Scenarios )
@@ -1188,6 +1189,7 @@ public async Task<IActionResult> Diagram(string scenarioId)
1188
1189
{
1189
1190
if ( ! User . Identity . IsAuthenticated ) { return RedirectToAction ( "Login" , "Security" ) ; }
1190
1191
1192
+ /* Deprecated GraphViz Code
1191
1193
List<string> document = new List<string>();
1192
1194
1193
1195
Scenarios scenario = await _scenariosService.GetByIdAsync(scenarioId);
@@ -1201,41 +1203,7 @@ public async Task<IActionResult> Diagram(string scenarioId)
1201
1203
1202
1204
// Fixing root node issue
1203
1205
var first = stepList.First();
1204
- if (
1205
- first . ThreatSource == "Outsider" ||
1206
- first . ThreatSource == "Insider" ||
1207
- first . ThreatSource == "Trusted Insider" ||
1208
- first . ThreatSource == "Privileged Insider"
1209
- )
1210
- {
1211
- nodeList . Add ( new Node ( null , "malicious-actor" , first . ThreatSource , "" , "root" ) ) ;
1212
- }
1213
- else if (
1214
- first . ThreatSource == "Partner Organization" ||
1215
- first . ThreatSource == "Competitor Organization" ||
1216
- first . ThreatSource == "Supplier Organization" ||
1217
- first . ThreatSource == "Customer Organization"
1218
- )
1219
- {
1220
- nodeList . Add ( new Node ( null , "group" , first . ThreatSource , "" , "root" ) ) ;
1221
- }
1222
- else if (
1223
- first . ThreatSource == "Ad Hoc Group" ||
1224
- first . ThreatSource == "Established Group"
1225
- )
1226
- {
1227
- nodeList . Add ( new Node ( null , "organization" , first . ThreatSource , "" , "root" ) ) ;
1228
- }
1229
- else if (
1230
- first . ThreatSource == "Nation State"
1231
- )
1232
- {
1233
- nodeList . Add ( new Node ( null , "guard-personnel" , first . ThreatSource , "" , "root" ) ) ;
1234
- }
1235
- else
1236
- {
1237
- nodeList . Add ( new Node ( null , "unknown-suspect" , first . ThreatSource , "" , "root" ) ) ;
1238
- }
1206
+
1239
1207
1240
1208
foreach (var step in stepList)
1241
1209
{
@@ -1341,7 +1309,133 @@ public async Task<IActionResult> Diagram(string scenarioId)
1341
1309
document.Add("\tfontsize=\"28\";");
1342
1310
document.Add("\tlabel=\"" + scenario.Name.Replace("\"", "\\\"") + "\";");
1343
1311
document.Add("}");
1312
+ */
1313
+
1314
+ // Hijacking flow for D3 //
1315
+
1316
+ Scenarios scenario = await _scenariosService . GetByIdAsync ( scenarioId ) ;
1317
+
1318
+ List < Steps > eventList = new List < Steps > ( ) ;
1319
+ foreach ( string stepId in scenario . Steps ) { eventList . Add ( await _stepsService . GetByIdAsync ( stepId ) ) ; }
1320
+
1321
+ string quoteEscaper = @"\" + "\" " ;
1322
+
1323
+ using ( StreamWriter outputFile = new StreamWriter ( Path . Combine ( "wwwroot/graphs/" , "graph.json" ) ) )
1324
+ {
1325
+ outputFile . WriteLine ( "{" ) ;
1326
+ outputFile . WriteLine ( "\" nodes\" : [" ) ;
1327
+ List < string > Ids = new List < string > ( ) ;
1328
+ List < ( string parent , string id , string risk , int step ) > links = new List < ( string parent , string id , string risk , int step ) > ( ) ;
1329
+ int counter = 0 ;
1330
+
1331
+ // Accounting for root node
1332
+ Ids . Add ( "" ) ;
1333
+
1334
+ // Setting icon according to first event threat actor
1335
+ var first = eventList . First ( ) ;
1336
+ string attackerIcon = "" ;
1337
+
1338
+ if (
1339
+ first . ThreatSource == "Outsider" ||
1340
+ first . ThreatSource == "Insider" ||
1341
+ first . ThreatSource == "Trusted Insider" ||
1342
+ first . ThreatSource == "Privileged Insider"
1343
+ )
1344
+ {
1345
+ attackerIcon = "malicious-actor" ;
1346
+ }
1347
+ else if (
1348
+ first . ThreatSource == "Partner Organization" ||
1349
+ first . ThreatSource == "Competitor Organization" ||
1350
+ first . ThreatSource == "Supplier Organization" ||
1351
+ first . ThreatSource == "Customer Organization"
1352
+ )
1353
+ {
1354
+ attackerIcon = "group" ;
1355
+ }
1356
+ else if (
1357
+ first . ThreatSource == "Ad Hoc Group" ||
1358
+ first . ThreatSource == "Established Group"
1359
+ )
1360
+ {
1361
+ attackerIcon = "organization" ;
1362
+ }
1363
+ else if (
1364
+ first . ThreatSource == "Nation State"
1365
+ )
1366
+ {
1367
+ attackerIcon = "guard-personnel" ;
1368
+ }
1369
+ else
1370
+ {
1371
+ attackerIcon = "unknown-suspect" ;
1372
+ }
1373
+
1374
+ outputFile . WriteLine ( "{" ) ;
1375
+ outputFile . WriteLine ( $ "\" x\" : 0,") ;
1376
+ outputFile . WriteLine ( $ "\" y\" : 0,") ;
1377
+ outputFile . WriteLine ( $ "\" title\" : \" { first . ThreatSource } \" ,") ;
1378
+ outputFile . WriteLine ( $ "\" icon\" : \" /icons/{ attackerIcon } .png\" ") ;
1379
+ outputFile . WriteLine ( "}," ) ;
1380
+
1381
+ foreach ( Steps ev in eventList )
1382
+ {
1383
+
1384
+ // Inject Node Information
1385
+ if ( ! Ids . Contains ( ev . Id ) ) { Ids . Add ( ev . Id ) ; }
1386
+ outputFile . WriteLine ( "{" ) ;
1387
+ outputFile . WriteLine ( "\" x\" : 0," ) ;
1388
+ outputFile . WriteLine ( "\" y\" : 0," ) ;
1389
+ outputFile . WriteLine ( $ "\" title\" : \" { ev . GraphNode . EntityDescription . Replace ( @"\" , @"\\" ) . Replace ( "\" " , quoteEscaper ) } \" ,") ;
1390
+ outputFile . WriteLine ( $ "\" icon\" : \" /icons/{ ev . GraphNode . EntityType } .png\" ") ;
1391
+
1392
+ string end = "}" ;
1393
+ if ( counter ++ < eventList . Count - 1 ) { end = end + "," ; }
1394
+ outputFile . WriteLine ( end ) ;
1395
+
1396
+ // Collect link information
1397
+ foreach ( string parentId in ev . GraphNode . ParentId )
1398
+ {
1399
+ string parent = "" ;
1400
+ if ( parentId != null ) { parent = parentId ; }
1401
+ links . Add ( ( parent , ev . Id , ev . Risk . ToLower ( ) . Replace ( " " , "-" ) , counter ) ) ;
1402
+ }
1403
+ }
1404
+ outputFile . WriteLine ( "]," ) ;
1405
+ outputFile . WriteLine ( "\" links\" : [" ) ;
1406
+ counter = 0 ;
1407
+ foreach ( var link in links )
1408
+ {
1409
+ outputFile . WriteLine ( "{" ) ;
1410
+ outputFile . WriteLine ( $ "\" source\" : { Ids . IndexOf ( link . parent ) } ,") ;
1411
+ outputFile . WriteLine ( $ "\" target\" : { Ids . IndexOf ( link . id ) } ,") ;
1412
+ outputFile . WriteLine ( $ "\" risk\" : \" { link . risk } \" ,") ;
1413
+ outputFile . WriteLine ( $ "\" label\" : \" { link . step } .\" ") ;
1414
+
1415
+ string end = "}" ;
1416
+ if ( counter ++ < links . Count - 1 ) { end = end + "," ; }
1417
+ outputFile . WriteLine ( end ) ;
1418
+ }
1419
+ outputFile . WriteLine ( "]" ) ;
1420
+ outputFile . WriteLine ( "}" ) ;
1421
+
1422
+ }
1423
+
1424
+ string markdownTable = "| Event |\n | ----- |\n " ;
1425
+ int eventCounter = 1 ;
1426
+ foreach ( var ev in eventList )
1427
+ {
1428
+ markdownTable += "| " + eventCounter ++ . ToString ( ) + ". " + ev . Event + " |\n " ;
1429
+ }
1430
+
1431
+ ViewBag . MarkdownTable = markdownTable ;
1432
+
1433
+ scenario . Name = scenario . Name . Replace ( " " , "_" ) ;
1434
+ return View ( scenario ) ;
1344
1435
1436
+ // End Hijacking, following code is deprecated
1437
+
1438
+ /*
1345
1439
// write the text to a DOT file
1346
1440
using (StreamWriter outputFile = new StreamWriter(Path.Combine("wwwroot/graphs/", "graph.dot")))
1347
1441
{
@@ -1373,6 +1467,7 @@ public async Task<IActionResult> Diagram(string scenarioId)
1373
1467
1374
1468
1375
1469
return View(stepList);
1470
+ */
1376
1471
}
1377
1472
1378
1473
#endregion
@@ -2579,6 +2674,58 @@ List<string> nodeShape
2579
2674
2580
2675
}
2581
2676
2677
+ public async Task < IActionResult > EditTreeCategories ( string [ ] categories , string [ ] colors , string threatTreeId , string assessmentId )
2678
+ {
2679
+ if ( ! User . Identity . IsAuthenticated ) { return RedirectToAction ( "Login" , "Security" ) ; }
2680
+
2681
+ ThreatTree tree = await _treeService . GetByIdAsync ( threatTreeId ) ;
2682
+
2683
+ // Build the new list of categories we want to use
2684
+ List < string [ ] > newCategories = new List < string [ ] > ( ) ;
2685
+ for ( int i = 0 ; i < categories . Length ; i ++ )
2686
+ {
2687
+ newCategories . Add ( new string [ ]
2688
+ {
2689
+ categories [ i ] , colors [ i ] , tree . ColorList . GetValueOrDefault ( colors [ i ] )
2690
+ } ) ;
2691
+ }
2692
+
2693
+ // Check to see which of the old categories are no longer used
2694
+ List < string > removeCategories = new List < string > ( ) ;
2695
+ foreach ( string [ ] category in tree . Categories )
2696
+ {
2697
+ if ( ! categories . Contains ( category [ 0 ] ) )
2698
+ {
2699
+ removeCategories . Add ( category [ 0 ] ) ;
2700
+ }
2701
+ }
2702
+
2703
+ // Reset each of the nodes which belongs to the removed categories
2704
+ foreach ( ThreatTreeNode node in tree . NodeList )
2705
+ {
2706
+ if ( removeCategories . Contains ( node . Classification [ 0 ] ) )
2707
+ {
2708
+ node . Classification = newCategories . First ( ) ;
2709
+ }
2710
+ // If it is not to be reset, verify the colors are up to date
2711
+ else
2712
+ {
2713
+ foreach ( string [ ] category in newCategories )
2714
+ {
2715
+ if ( node . Classification [ 0 ] == category [ 0 ] ) { node . Classification = category ; break ; }
2716
+ }
2717
+ }
2718
+ }
2719
+
2720
+ // Set the tree categories to our new list
2721
+ tree . Categories = newCategories ;
2722
+
2723
+ // Update the tree
2724
+ await _treeService . UpdateAsync ( tree . Id , tree ) ;
2725
+
2726
+ return RedirectToAction ( "EditTree" , "Home" , new { threatTreeId = tree . Id , assessmentId = assessmentId } ) ;
2727
+ }
2728
+
2582
2729
public async Task < IActionResult > ExportTree ( string treeId )
2583
2730
{
2584
2731
if ( ! User . Identity . IsAuthenticated ) { return RedirectToAction ( "Login" , "Security" ) ; }
@@ -2612,10 +2759,11 @@ public async Task<IActionResult> ExportTree(string treeId)
2612
2759
2613
2760
// Build out the subgraphs
2614
2761
foreach ( var category in tree . Categories )
2615
- {
2616
- // Handle Clustering
2617
- if ( tree . IsClustered ) { document . Add ( "\t subgraph cluster_" + category [ 0 ] . Replace ( " " , "" ) . ToLower ( ) + " {" ) ; }
2618
- else { document . Add ( "\t subgraph " + category [ 0 ] . Replace ( " " , "" ) . ToLower ( ) + " {" ) ; }
2762
+ {
2763
+ // Handle Clustering
2764
+ string cleanCategory = Regex . Replace ( category [ 0 ] , "[^0-9a-zA-Z_]+" , "_" ) ;
2765
+ if ( tree . IsClustered ) { document . Add ( "\t subgraph cluster_" + cleanCategory . ToLower ( ) + " {" ) ; }
2766
+ else { document . Add ( "\t subgraph " + cleanCategory . ToLower ( ) + " {" ) ; }
2619
2767
2620
2768
2621
2769
List < string > nodesInSubgraph = new List < string > ( ) ;
@@ -2771,7 +2919,8 @@ public async Task<IActionResult> ExportTree(string treeId)
2771
2919
string legendEdge = "" ;
2772
2920
foreach ( var category in tree . Categories )
2773
2921
{
2774
- document . Add ( "\t subgraph " + category [ 0 ] . Replace ( " " , "" ) . ToLower ( ) + " {" ) ;
2922
+ string cleanCategory = Regex . Replace ( category [ 0 ] , "[^0-9a-zA-Z_]+" , "_" ) ;
2923
+ document . Add ( "\t subgraph " + cleanCategory . ToLower ( ) + " {" ) ;
2775
2924
document . Add ( "\t \t " + legendCounter + " [color=" + category [ 1 ] + ",style=\" rounded,filled\" ,shape=box,label=\" " + category [ 0 ] + "\" ];" ) ;
2776
2925
document . Add ( "\t \t {rank=same; " + legendCounter + ";}" ) ;
2777
2926
document . Add ( "\t }" ) ;
@@ -2813,6 +2962,15 @@ public async Task<IActionResult> ExportTree(string treeId)
2813
2962
if ( string . IsNullOrEmpty ( error ) ) { Console . WriteLine ( output ) ; }
2814
2963
else { Console . WriteLine ( error ) ; }
2815
2964
2965
+ string treePath = @"wwwroot/graphs/Tree.png" ;
2966
+ string legendPath = @"wwwroot/graphs/Legend.png" ;
2967
+
2968
+ DateTime treeDate = System . IO . File . GetLastWriteTime ( treePath ) ;
2969
+ DateTime legendDate = System . IO . File . GetLastWriteTime ( legendPath ) ;
2970
+
2971
+ ViewBag . TreeDate = treeDate ;
2972
+ ViewBag . LegendDate = legendDate ;
2973
+
2816
2974
return View ( ) ;
2817
2975
}
2818
2976
0 commit comments