Skip to content

Commit 68ff793

Browse files
Merge pull request #283 from ImYrS/master
feat: support .cm ccTLD
2 parents 2ef0bf6 + f64f8b3 commit 68ff793

3 files changed

Lines changed: 77 additions & 1 deletion

File tree

test/test_parser.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,54 @@ def test_bw_parse(self):
841841
}
842842
self._parse_and_compare("google.co.bw", data, expected_results)
843843

844+
def test_cm_parse(self):
845+
data = """
846+
Domain Name: icp.cm
847+
Registry Domain ID: 1104110-RegCM
848+
Updated Date: 2025-05-27T04:46:44.214Z
849+
Creation Date: 2024-08-24T13:17:43.633Z
850+
Registry Expiry Date: 2026-08-24T13:17:44.316Z
851+
Domain Status: ok https://icann.org/epp#ok
852+
Registrar: Netcom.cm Sarl
853+
Reseller: NetSto Inc. - https://www.netsto.com
854+
Name Server: ns1.huaweicloud-dns.com
855+
Name Server: ns1.huaweicloud-dns.net
856+
Name Server: ns1.huaweicloud-dns.cn
857+
Name Server: ns1.huaweicloud-dns.org
858+
>>> Last update of WHOIS database: 2025-05-28T04:47:00.968Z <<<
859+
860+
For more information on EPP status codes, please visit https://icann.org/epp
861+
862+
TERMS OF USE: You are not authorized to access or query our Whois
863+
database through the use of electronic processes that are high-volume and
864+
automated. Whois database is provided by ANTIC as a service to the internet
865+
community on behalf of ANTIC accredited registrars and resellers.
866+
867+
The data is for information purposes only. ANTIC does not
868+
guarantee its accuracy. By submitting a Whois query, you agree to abide
869+
by the following terms of use: You agree that you may use this Data only
870+
for lawful purposes and that under no circumstances will you use this Data
871+
to: (1) allow, enable, or otherwise support the transmission of mass
872+
unsolicited, commercial advertising or solicitations via e-mail, telephone,
873+
or facsimile; or (2) enable high volume, automated, electronic processes
874+
that apply to ANTIC members (or their computer systems). The
875+
compilation, repackaging, dissemination or other use of this Data is prohibited.
876+
"""
877+
878+
expected_results = {
879+
"domain_name": "icp.cm",
880+
"registry_domain_id": "1104110-RegCM",
881+
"updated_date": datetime.datetime(2025, 5, 27, 4, 46, 44, 214000),
882+
"creation_date": datetime.datetime(2024, 8, 24, 13, 17, 43, 633000),
883+
"expiration_date": datetime.datetime(2026, 8, 24, 13, 17, 44, 316000),
884+
"status": "ok https://icann.org/epp#ok",
885+
"registrar": "Netcom.cm Sarl",
886+
"reseller": "NetSto Inc. - https://www.netsto.com",
887+
"name_servers": ['ns1.huaweicloud-dns.com', 'ns1.huaweicloud-dns.net', 'ns1.huaweicloud-dns.cn',
888+
'ns1.huaweicloud-dns.org']
889+
}
890+
self._parse_and_compare("icp.cm", data, expected_results)
891+
844892

845893
if __name__ == "__main__":
846894
unittest.main()

whois/parser.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"%Y-%b-%d.", # 2024-Apr-02.
7272
]
7373

74+
7475
def datetime_parse(s: str) -> Union[str, datetime]:
7576
for known_format in KNOWN_FORMATS:
7677
try:
@@ -413,6 +414,8 @@ def load(domain: str, text: str):
413414
return WhoisCo(domain, text)
414415
elif domain.endswith(".ga"):
415416
return WhoisGa(domain, text)
417+
elif domain.endswith(".cm"):
418+
return WhoisCm(domain, text)
416419
else:
417420
return WhoisEntry(domain, text)
418421

@@ -441,7 +444,7 @@ def __init__(self, domain: str, text: str):
441444
text,
442445
self.regex,
443446
lambda x: x.replace(" CLST", "").replace(" CLT", "")
444-
)
447+
)
445448

446449

447450
class WhoisSG(WhoisEntry):
@@ -3465,6 +3468,7 @@ def __init__(self, domain: str, text: str):
34653468
else:
34663469
WhoisEntry.__init__(self, domain, text, self.regex)
34673470

3471+
34683472
class WhoisGa(WhoisEntry):
34693473
"""Whois parser for .ga domains"""
34703474

@@ -3497,3 +3501,24 @@ def __init__(self, domain, text):
34973501
else:
34983502
WhoisEntry.__init__(self, domain, text, self.regex)
34993503

3504+
3505+
class WhoisCm(WhoisEntry):
3506+
"""Whois parser for .cm domains"""
3507+
3508+
regex: dict[str, str] = {
3509+
"domain_name": r"Domain Name: *(.+)",
3510+
"registry_domain_id": r"Registry Domain ID: *(.+)",
3511+
"registrar": r"Registrar: *(.+)",
3512+
"reseller": r"Reseller: *(.+)",
3513+
"updated_date": r"Updated Date: *(.+)",
3514+
"creation_date": r"Creation Date: *(.+)",
3515+
"expiration_date": r"Expir\w+ Date: *(.+)",
3516+
"name_servers": r"Name Server: *(.+)", # list of name servers
3517+
"status": r"Status: *(.+)", # list of statuses
3518+
}
3519+
3520+
def __init__(self, domain: str, text: str):
3521+
if 'No match for "' in text:
3522+
raise WhoisDomainNotFoundError(text)
3523+
else:
3524+
WhoisEntry.__init__(self, domain, text, self.regex)

whois/whois.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class NICClient:
5050
CA_HOST = "whois.ca.fury.ca"
5151
CHAT_HOST = "whois.nic.chat"
5252
CL_HOST = "whois.nic.cl"
53+
CM_HOST = "whois.netcom.cm"
5354
CR_HOST = "whois.nic.cr"
5455
DEFAULT_PORT = "nicname"
5556
DENICHOST = "whois.denic.de"
@@ -293,6 +294,8 @@ def choose_server(self, domain: str) -> Optional[str]:
293294
return NICClient.CHAT_HOST
294295
elif tld == "cl":
295296
return NICClient.CL_HOST
297+
elif tld == "cm":
298+
return NICClient.CM_HOST
296299
elif tld == "cr":
297300
return NICClient.CR_HOST
298301
elif tld == "de":

0 commit comments

Comments
 (0)