Fossil SCM
Add the /phantoms webpage that lists public phantom artifacts. Check the number of public phantom artifacts and puts a warning if the number is non-zero on the Security Audit page.
Commit
83db244395090d8365b64c12e7b3a4d8896eb3dba76ef77042f37344c2b07f25
Parent
4c444c1c8868929…
2 files changed
+64
+18
+64
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -1325,10 +1325,74 @@ | ||
| 1325 | 1325 | } |
| 1326 | 1326 | }else{ |
| 1327 | 1327 | @ <td> |
| 1328 | 1328 | } |
| 1329 | 1329 | @ </tr> |
| 1330 | + } | |
| 1331 | + @ </table> | |
| 1332 | + db_finalize(&q); | |
| 1333 | + style_footer(); | |
| 1334 | +} | |
| 1335 | + | |
| 1336 | +/* | |
| 1337 | +** WEBPAGE: phantoms | |
| 1338 | +** | |
| 1339 | +** Show a list of all "phantom" artifacts that are not marked as "private". | |
| 1340 | +** | |
| 1341 | +** A "phantom" artifact is an artifact whose hash named appears in some | |
| 1342 | +** artifact but whose content is unknown. For example, if a manifest | |
| 1343 | +** references a particular SHA3 hash of a file, but that SHA3 hash is | |
| 1344 | +** not on the shunning list and is not in the database, then the file | |
| 1345 | +** is a phantom. We know it exists, but we do not know its content. | |
| 1346 | +** | |
| 1347 | +** Whenever a sync occurs, both each party looks at its phantom list | |
| 1348 | +** and for every phantom that is not also marked private, it asks the | |
| 1349 | +** other party to send it the content. This mechanism helps keep all | |
| 1350 | +** repositories synced up. | |
| 1351 | +** | |
| 1352 | +** This page is similar to the /bloblist page in that it lists artifacts. | |
| 1353 | +** But this page is a special case in that it only shows phantoms that | |
| 1354 | +** are not private. In other words, this page shows all phantoms that | |
| 1355 | +** generate extra network traffic on every sync request. | |
| 1356 | +*/ | |
| 1357 | +void phantom_list_page(void){ | |
| 1358 | + Stmt q; | |
| 1359 | + char *zRange; | |
| 1360 | + | |
| 1361 | + login_check_credentials(); | |
| 1362 | + if( !g.perm.Read ){ login_needed(g.anon.Read); return; } | |
| 1363 | + style_header("Public Phantom Artifacts"); | |
| 1364 | + if( g.perm.Admin ){ | |
| 1365 | + style_submenu_element("Artifact Log", "rcvfromlist"); | |
| 1366 | + style_submenu_element("Artifact List", "bloblist"); | |
| 1367 | + } | |
| 1368 | + if( g.perm.Write ){ | |
| 1369 | + style_submenu_element("Artifact Stats", "artifact_stats"); | |
| 1370 | + } | |
| 1371 | + zRange = mprintf("IN (SELECT rid FROM phantom EXCEPT" | |
| 1372 | + " SELECT rid FROM private)"); | |
| 1373 | + describe_artifacts(zRange); | |
| 1374 | + fossil_free(zRange); | |
| 1375 | + db_prepare(&q, | |
| 1376 | + "SELECT rid, uuid, summary, ref" | |
| 1377 | + " FROM description ORDER BY rid" | |
| 1378 | + ); | |
| 1379 | + @ <table cellpadding="2" cellspacing="0" border="1"> | |
| 1380 | + @ <tr><th>RID<th>Description<th>Source | |
| 1381 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 1382 | + int rid = db_column_int(&q,0); | |
| 1383 | + const char *zUuid = db_column_text(&q, 1); | |
| 1384 | + const char *zDesc = db_column_text(&q, 2); | |
| 1385 | + const char *zRef = db_column_text(&q,3); | |
| 1386 | + @ <tr><td valign="top">%d(rid)</td> | |
| 1387 | + @ <td valign="top" align="left">%h(zUuid)<br>%h(zDesc)</td> | |
| 1388 | + if( zRef && zRef[0] ){ | |
| 1389 | + @ <td valign="top">%z(href("%R/info/%!S",zRef))%!S(zRef)</a> | |
| 1390 | + }else{ | |
| 1391 | + @ <td> | |
| 1392 | + } | |
| 1393 | + @ </tr> | |
| 1330 | 1394 | } |
| 1331 | 1395 | @ </table> |
| 1332 | 1396 | db_finalize(&q); |
| 1333 | 1397 | style_footer(); |
| 1334 | 1398 | } |
| 1335 | 1399 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -1325,10 +1325,74 @@ | |
| 1325 | } |
| 1326 | }else{ |
| 1327 | @ <td> |
| 1328 | } |
| 1329 | @ </tr> |
| 1330 | } |
| 1331 | @ </table> |
| 1332 | db_finalize(&q); |
| 1333 | style_footer(); |
| 1334 | } |
| 1335 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -1325,10 +1325,74 @@ | |
| 1325 | } |
| 1326 | }else{ |
| 1327 | @ <td> |
| 1328 | } |
| 1329 | @ </tr> |
| 1330 | } |
| 1331 | @ </table> |
| 1332 | db_finalize(&q); |
| 1333 | style_footer(); |
| 1334 | } |
| 1335 | |
| 1336 | /* |
| 1337 | ** WEBPAGE: phantoms |
| 1338 | ** |
| 1339 | ** Show a list of all "phantom" artifacts that are not marked as "private". |
| 1340 | ** |
| 1341 | ** A "phantom" artifact is an artifact whose hash named appears in some |
| 1342 | ** artifact but whose content is unknown. For example, if a manifest |
| 1343 | ** references a particular SHA3 hash of a file, but that SHA3 hash is |
| 1344 | ** not on the shunning list and is not in the database, then the file |
| 1345 | ** is a phantom. We know it exists, but we do not know its content. |
| 1346 | ** |
| 1347 | ** Whenever a sync occurs, both each party looks at its phantom list |
| 1348 | ** and for every phantom that is not also marked private, it asks the |
| 1349 | ** other party to send it the content. This mechanism helps keep all |
| 1350 | ** repositories synced up. |
| 1351 | ** |
| 1352 | ** This page is similar to the /bloblist page in that it lists artifacts. |
| 1353 | ** But this page is a special case in that it only shows phantoms that |
| 1354 | ** are not private. In other words, this page shows all phantoms that |
| 1355 | ** generate extra network traffic on every sync request. |
| 1356 | */ |
| 1357 | void phantom_list_page(void){ |
| 1358 | Stmt q; |
| 1359 | char *zRange; |
| 1360 | |
| 1361 | login_check_credentials(); |
| 1362 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1363 | style_header("Public Phantom Artifacts"); |
| 1364 | if( g.perm.Admin ){ |
| 1365 | style_submenu_element("Artifact Log", "rcvfromlist"); |
| 1366 | style_submenu_element("Artifact List", "bloblist"); |
| 1367 | } |
| 1368 | if( g.perm.Write ){ |
| 1369 | style_submenu_element("Artifact Stats", "artifact_stats"); |
| 1370 | } |
| 1371 | zRange = mprintf("IN (SELECT rid FROM phantom EXCEPT" |
| 1372 | " SELECT rid FROM private)"); |
| 1373 | describe_artifacts(zRange); |
| 1374 | fossil_free(zRange); |
| 1375 | db_prepare(&q, |
| 1376 | "SELECT rid, uuid, summary, ref" |
| 1377 | " FROM description ORDER BY rid" |
| 1378 | ); |
| 1379 | @ <table cellpadding="2" cellspacing="0" border="1"> |
| 1380 | @ <tr><th>RID<th>Description<th>Source |
| 1381 | while( db_step(&q)==SQLITE_ROW ){ |
| 1382 | int rid = db_column_int(&q,0); |
| 1383 | const char *zUuid = db_column_text(&q, 1); |
| 1384 | const char *zDesc = db_column_text(&q, 2); |
| 1385 | const char *zRef = db_column_text(&q,3); |
| 1386 | @ <tr><td valign="top">%d(rid)</td> |
| 1387 | @ <td valign="top" align="left">%h(zUuid)<br>%h(zDesc)</td> |
| 1388 | if( zRef && zRef[0] ){ |
| 1389 | @ <td valign="top">%z(href("%R/info/%!S",zRef))%!S(zRef)</a> |
| 1390 | }else{ |
| 1391 | @ <td> |
| 1392 | } |
| 1393 | @ </tr> |
| 1394 | } |
| 1395 | @ </table> |
| 1396 | db_finalize(&q); |
| 1397 | style_footer(); |
| 1398 | } |
| 1399 |
+18
| --- src/security_audit.c | ||
| +++ src/security_audit.c | ||
| @@ -553,10 +553,28 @@ | ||
| 553 | 553 | stats_for_email(); |
| 554 | 554 | @ </table> |
| 555 | 555 | }else{ |
| 556 | 556 | @ <li><p> Email alerts are disabled |
| 557 | 557 | } |
| 558 | + | |
| 559 | + n = db_int(0,"SELECT count(*) FROM (" | |
| 560 | + "SELECT rid FROM phantom EXCEPT SELECT rid FROM private)"); | |
| 561 | + if( n>0 ){ | |
| 562 | + @ <li><p>\ | |
| 563 | + if( n==1 ){ | |
| 564 | + @ There is 1 public phantom artifact | |
| 565 | + }else{ | |
| 566 | + @ There are %d(n) public phantom artifacts | |
| 567 | + } | |
| 568 | + @ (<a href="%R/phantoms">details</a>). | |
| 569 | + @ Phantom artifacts are artifacts whose hash name is referenced by some | |
| 570 | + @ other artifact but whose content is unknown. Some phantoms are marked | |
| 571 | + @ private and those are ignored. But public phantoms cause unnecessary | |
| 572 | + @ sync traffic and might represent malicious attempts to corrupt the | |
| 573 | + @ repository structure. | |
| 574 | + @ </p></li> | |
| 575 | + } | |
| 558 | 576 | |
| 559 | 577 | @ </ol> |
| 560 | 578 | style_footer(); |
| 561 | 579 | } |
| 562 | 580 | |
| 563 | 581 |
| --- src/security_audit.c | |
| +++ src/security_audit.c | |
| @@ -553,10 +553,28 @@ | |
| 553 | stats_for_email(); |
| 554 | @ </table> |
| 555 | }else{ |
| 556 | @ <li><p> Email alerts are disabled |
| 557 | } |
| 558 | |
| 559 | @ </ol> |
| 560 | style_footer(); |
| 561 | } |
| 562 | |
| 563 |
| --- src/security_audit.c | |
| +++ src/security_audit.c | |
| @@ -553,10 +553,28 @@ | |
| 553 | stats_for_email(); |
| 554 | @ </table> |
| 555 | }else{ |
| 556 | @ <li><p> Email alerts are disabled |
| 557 | } |
| 558 | |
| 559 | n = db_int(0,"SELECT count(*) FROM (" |
| 560 | "SELECT rid FROM phantom EXCEPT SELECT rid FROM private)"); |
| 561 | if( n>0 ){ |
| 562 | @ <li><p>\ |
| 563 | if( n==1 ){ |
| 564 | @ There is 1 public phantom artifact |
| 565 | }else{ |
| 566 | @ There are %d(n) public phantom artifacts |
| 567 | } |
| 568 | @ (<a href="%R/phantoms">details</a>). |
| 569 | @ Phantom artifacts are artifacts whose hash name is referenced by some |
| 570 | @ other artifact but whose content is unknown. Some phantoms are marked |
| 571 | @ private and those are ignored. But public phantoms cause unnecessary |
| 572 | @ sync traffic and might represent malicious attempts to corrupt the |
| 573 | @ repository structure. |
| 574 | @ </p></li> |
| 575 | } |
| 576 | |
| 577 | @ </ol> |
| 578 | style_footer(); |
| 579 | } |
| 580 | |
| 581 |