trwnh / namecheap

certbot manual auth hook for DNS-01 with namecheap
GNU Affero General Public License v3.0
14 stars 15 forks source link

Handle public suffixes that contain dots correctly #3

Open maservant opened 8 months ago

maservant commented 8 months ago

Right now the top-level domain and second-level domain are derived by splitting off the substring that follows the last dot.

For example, if the environment variable CERTBOT_DOMAIN=my.blog.example.com, the script will correctly identify:

subdomain = 'my.blog'
SLD = 'example'
TLD = 'com'

But for something like eggs-with-spam.co.uk, the script would wrongly identify:

subdomain = 'eggs-with-spam'
SLD = 'co'
TLD = 'uk'

The correct behaviour would be:

subdomain = '' # Empty string
SLD = 'eggs-with-spam'
TLD = 'co.uk'

Unfortunately this would require either an API from Namecheap that can identify which part of your registered domain is the SLD and which is the TLD, which is not a trivial task. One could make an HTTP GET request to namecheap.domains.getTldList, but that would fail to identify TLDs that are no longer registered but where existing registrations are grandfathered in (for example, domain.[province code].ca). If you suspect your domain's public suffix has a dot in it (a good starting point is the Public Suffix List), do not use this script unless you want to mess up every single one of your DNS records.

I'm currently working on a solution that handles those cases gracefully.

elliotwutingfeng commented 7 months ago

May I recommend the tldextract library for this task. It is also capable of using custom public suffix lists, should mozilla's list not meet your requirements.

maservant commented 7 months ago

@elliotwutingfeng This seems like a great idea, especially given that those lists can get pretty big, and the library you suggested uses caching. The concern I have is that if we get this wrong, we might wipe the user's entire DNS entries with the namecheap.domains.dns.setHosts API call.

My suggestion would be to

  1. Use the user-provided API key to make a GET request to namecheap.domains.getTldList and cache the response. This would require adding an optional dependency to the requests-cache PyPi package (if requests-cache is installed, cache the response, if not, then make a new request every time but warn the user to install requests-cache to not accidentally DoS the Namecheap API)
  2. Use the tldextract as you mentionned above to extract the public suffix from the CERTBOT_DOMAIN environment variable
  3. Check if the answer from step 2 matches an entry in step 1. If it does, we're good. If if doesn't, then out of an abundance of precaution the script should exit with an error. This condition should only happen for domains that are:
    • Registered with Namecheap.
    • Using a public suffix that Namecheap doesn't accept domain registrations for.
  4. If the public suffix returned in step 2 does match an entry listed in step 1, then we can safely assume this is the TLD and run the rest of the script under that assumption.

As mentionned in my above comment, this should really be an issue where the organisation sponsoring the TLD dropped support for new registrations under that suffix (such as domain.[province code].ca) but existing registrations were grandfathered in. Very few users would be affected.

I'll be in Ottawa tomorrow so I will likely try this on Monday evening. Thanks for pointing me in the right direction!

maservant commented 7 months ago

I'd like to add that I don't own any grandfathered domains of the form sorry-from-canada.qc.ca and that even if I did, I would be prohibited by the grandfathering rules from transferring it to Namecheap. Therefore we'd likely need a British volunteer with both god-save-the-king.uk and god-save-the-king.co.uk to test the fix. I might be wrong, but I don't think I'm allowed to register a .co.uk as a citizen of Canada.