@@ -215,8 +215,20 @@ def _html_source_metadata(
215215 return source_key , source_name
216216
217217
218+ def _is_safe_url (url : str ) -> bool :
219+ try :
220+ return urlparse (url ).scheme in ("http" , "https" )
221+ except ValueError :
222+ return False
223+
224+
225+ def _safe_notice_url (row : Row ) -> str :
226+ url = str (row .get ("notice_url" , "" ) or row .get ("organization_name_url" , "" ) or "" ).strip ()
227+ return url if _is_safe_url (url ) else ""
228+
229+
218230def _html_notice_link (row : Row ) -> str :
219- notice_url = str (row . get ( "notice_url" , "" ) or row . get ( "organization_name_url" , "" ) or "" )
231+ notice_url = _safe_notice_url (row )
220232 if not notice_url :
221233 return ""
222234 return (
@@ -240,9 +252,9 @@ def _html_source_link(row: Row, source_name: str) -> str:
240252
241253def _html_organization_link (row : Row ) -> str :
242254 organization_name = str (row .get ("organization_name" , "" ) or "Unknown organization" )
243- organization_url = str (row .get ("organization_name_url" , "" ) or "" )
255+ organization_url = str (row .get ("organization_name_url" , "" ) or "" ). strip ()
244256 safe_name = html .escape (organization_name )
245- if not organization_url :
257+ if not _is_safe_url ( organization_url ) :
246258 return safe_name
247259 return (
248260 f'<a href="{ html .escape (organization_url , quote = True )} " target="_blank" rel="noopener noreferrer">'
@@ -275,13 +287,16 @@ def _html_reported_date(row: Row) -> str:
275287
276288
277289def _html_affected_count (row : Row ) -> str :
278- return str (
279- row .get ("persons_affected" , "" )
280- or row .get ("total_persons_affected" , "" )
281- or row .get ("number_affected" , "" )
282- or row .get ("individuals_affected" , "" )
283- or ""
284- )
290+ for key in (
291+ "persons_affected" ,
292+ "total_persons_affected" ,
293+ "number_affected" ,
294+ "individuals_affected" ,
295+ ):
296+ value = row .get (key )
297+ if value is not None and value != "" :
298+ return str (value )
299+ return ""
285300
286301
287302def to_html (
@@ -356,7 +371,7 @@ def to_html(
356371 f'data-sort-date_of_breach="{ html .escape (_date_sort_key (breach_display ), quote = True )} " '
357372 f'data-sort-affected="{ affected_numeric if affected_numeric is not None else 0 } " '
358373 f'data-sort-information="{ html .escape (str (row .get ("information_compromised" , "" ) or "" ).casefold (), quote = True )} " '
359- f'data-sort-notice="{ html .escape (str (row . get ( "notice_url" , "" ) or row . get ( "organization_name_url" , "" ) or "" ), quote = True )} "'
374+ f'data-sort-notice="{ html .escape (_safe_notice_url (row ), quote = True )} "'
360375 f">"
361376 f'<td class="source-cell">{ _html_source_link (row , source_name )} </td>'
362377 f"<td>{ html .escape (reported_display or 'Unknown' )} </td>"
@@ -963,10 +978,7 @@ def to_report(
963978 lines .append (f"### { idx } . { name } " )
964979 lines .append (f"- Date reported: { row .get ('date_reported' , '' ) or 'Unknown' } " )
965980 lines .append (f"- Date of breach: { row .get ('date_of_breach' , '' ) or 'Unknown' } " )
966- lines .append (
967- "- Persons affected: "
968- f"{ row .get ('persons_affected' , '' ) or row .get ('total_persons_affected' , '' ) or row .get ('number_affected' , '' ) or row .get ('individuals_affected' , '' ) or 'Unknown' } "
969- )
981+ lines .append (f"- Persons affected: { _html_affected_count (row ) or 'Unknown' } " )
970982 lines .append (
971983 f"- Information compromised: { row .get ('information_compromised' , '' ) or 'Not listed' } "
972984 )
0 commit comments