1+ """Provide a data model for domains and some utility functions."""
2+
13# Standard Python Libraries
24from collections import OrderedDict
35from datetime import datetime , timedelta
1214
1315def get_psl ():
1416 """
15- Gets the Public Suffix List - either new, or cached in the CWD for 24 hours
17+ Get the Public Suffix List - either new, or cached in the CWD for 24 hours.
1618
1719 Returns
1820 -------
@@ -42,14 +44,14 @@ def download_psl():
4244
4345
4446def get_public_suffix (domain ):
45- """Returns the public suffix of a given domain"""
47+ """Return the public suffix of a given domain. """
4648 public_list = get_psl ()
4749
4850 return public_list .get_public_suffix (domain )
4951
5052
5153def format_list (record_list ):
52- """Format a list into a string to increase readability in CSV"""
54+ """Format a list into a string to increase readability in CSV. """
5355 # record_list should only be a list, not an integer, None, or
5456 # anything else. Thus this if clause handles only empty
5557 # lists. This makes a "null" appear in the JSON output for
@@ -61,7 +63,9 @@ def format_list(record_list):
6163
6264
6365class Domain :
64- base_domains : Dict [str , Domain ] = {}
66+ """Store information about a domain."""
67+
68+ base_domains : Dict [str , "Domain" ] = {}
6569
6670 def __init__ (
6771 self ,
@@ -73,6 +77,7 @@ def __init__(
7377 smtp_cache ,
7478 dns_hostnames ,
7579 ):
80+ """Retrieve information about a given domain name."""
7681 self .domain_name = domain_name .lower ()
7782
7883 self .base_domain_name = get_public_suffix (self .domain_name )
@@ -137,15 +142,13 @@ def __init__(
137142 self .ports_tested = set ()
138143
139144 def has_mail (self ):
145+ """Check if there are any mail servers associated with this domain."""
140146 if self .mail_servers is not None :
141147 return len (self .mail_servers ) > 0
142148 return None
143149
144150 def has_supports_smtp (self ):
145- """
146- Returns True if any of the mail servers associated with this
147- domain are listening and support SMTP.
148- """
151+ """Check if any of the mail servers associated with this domain are listening and support SMTP."""
149152 result = None
150153 if len (self .starttls_results ) > 0 :
151154 result = (
@@ -160,10 +163,7 @@ def has_supports_smtp(self):
160163 return result
161164
162165 def has_starttls (self ):
163- """
164- Returns True if any of the mail servers associated with this
165- domain are listening and support STARTTLS.
166- """
166+ """Check if any of the mail servers associated with this domain are listening and support STARTTLS."""
167167 result = None
168168 if len (self .starttls_results ) > 0 :
169169 result = (
@@ -178,16 +178,19 @@ def has_starttls(self):
178178 return result
179179
180180 def has_spf (self ):
181+ """Check if this domain has any Sender Policy Framework records."""
181182 if self .spf is not None :
182183 return len (self .spf ) > 0
183184 return None
184185
185186 def has_dmarc (self ):
187+ """Check if this domain has a Domain-based Message Authentication, Reporting, and Conformance record."""
186188 if self .dmarc is not None :
187189 return len (self .dmarc ) > 0
188190 return None
189191
190192 def add_mx_record (self , record ):
193+ """Add a mail server record for this domain."""
191194 if self .mx_records is None :
192195 self .mx_records = []
193196 self .mx_records .append (record )
@@ -198,30 +201,35 @@ def add_mx_record(self, record):
198201 self .mail_servers .append (record .exchange .to_text ().rstrip ("." ).lower ())
199202
200203 def parent_has_dmarc (self ):
204+ """Check if a domain or its parent has a Domain-based Message Authentication, Reporting, and Conformance record."""
201205 ans = self .has_dmarc ()
202206 if self .base_domain :
203207 ans = self .base_domain .has_dmarc ()
204208 return ans
205209
206210 def parent_dmarc_dnssec (self ):
211+ """Get this domain or its parent's DMARC DNSSEC information."""
207212 ans = self .dmarc_dnssec
208213 if self .base_domain :
209214 ans = self .base_domain .dmarc_dnssec
210215 return ans
211216
212217 def parent_valid_dmarc (self ):
218+ """Check if this domain or its parent have a valid DMARC record."""
213219 ans = self .valid_dmarc
214220 if self .base_domain :
215221 return self .base_domain .valid_dmarc
216222 return ans
217223
218224 def parent_dmarc_results (self ):
225+ """Get this domain or its parent's DMARC information."""
219226 ans = format_list (self .dmarc )
220227 if self .base_domain :
221228 ans = format_list (self .base_domain .dmarc )
222229 return ans
223230
224231 def get_dmarc_policy (self ):
232+ """Get this domain or its parent's DMARC policy."""
225233 ans = self .dmarc_policy
226234 # If the policy was never set, or isn't in the list of valid
227235 # policies, check the parents.
@@ -239,6 +247,7 @@ def get_dmarc_policy(self):
239247 return ans
240248
241249 def get_dmarc_subdomain_policy (self ):
250+ """Get this domain or its parent's DMARC subdomain policy."""
242251 ans = self .dmarc_subdomain_policy
243252 # If the policy was never set, or isn't in the list of valid
244253 # policies, check the parents.
@@ -250,41 +259,47 @@ def get_dmarc_subdomain_policy(self):
250259 return ans
251260
252261 def get_dmarc_pct (self ):
262+ """Get this domain or its parent's DMARC percentage information."""
253263 ans = self .dmarc_pct
254264 if not ans and self .base_domain :
255265 # Check the parents
256266 ans = self .base_domain .get_dmarc_pct ()
257267 return ans
258268
259269 def get_dmarc_has_aggregate_uri (self ):
270+ """Get this domain or its parent's DMARC aggregate URI."""
260271 ans = self .dmarc_has_aggregate_uri
261272 # If there are no aggregate URIs then check the parents.
262273 if not ans and self .base_domain :
263274 ans = self .base_domain .get_dmarc_has_aggregate_uri ()
264275 return ans
265276
266277 def get_dmarc_has_forensic_uri (self ):
278+ """Check if this domain or its parent have a DMARC forensic URI."""
267279 ans = self .dmarc_has_forensic_uri
268280 # If there are no forensic URIs then check the parents.
269281 if not ans and self .base_domain :
270282 ans = self .base_domain .get_dmarc_has_forensic_uri ()
271283 return ans
272284
273285 def get_dmarc_aggregate_uris (self ):
286+ """Get this domain or its parent's DMARC aggregate URIs."""
274287 ans = self .dmarc_aggregate_uris
275288 # If there are no aggregate URIs then check the parents.
276289 if not ans and self .base_domain :
277290 ans = self .base_domain .get_dmarc_aggregate_uris ()
278291 return ans
279292
280293 def get_dmarc_forensic_uris (self ):
294+ """Get this domain or its parent's DMARC forensic URIs."""
281295 ans = self .dmarc_forensic_uris
282296 # If there are no forensic URIs then check the parents.
283297 if not ans and self .base_domain :
284298 ans = self .base_domain .get_dmarc_forensic_uris ()
285299 return ans
286300
287301 def generate_results (self ):
302+ """Generate the results for this domain."""
288303 if len (self .starttls_results .keys ()) == 0 :
289304 domain_supports_smtp = None
290305 domain_supports_starttls = None
0 commit comments