freenom-0.0.2/0000755000175000017500000000000013651115351012545 5ustar shmshm00000000000000freenom-0.0.2/freenom/0000755000175000017500000000000013651115351014200 5ustar shmshm00000000000000freenom-0.0.2/freenom/__init__.py0000644000175000017500000002661713651027447016335 0ustar shmshm00000000000000# -*- coding: utf-8 -*- """ :author: Punk Lee :datetime: 2020/4/21 22:02 :url: https://punk_lee.gitee.io/ :copyright: ©2020 Punk Lee """ import requests, os, json from sys import exit from lxml.html import etree from retrying import retry from datetime import datetime from http.cookiejar import MozillaCookieJar def secure_retry(f): from functools import wraps @wraps(f) def inner(*args, **kwargs): try: return f(*args, **kwargs) except Exception as e: print(e) exit() return inner def _retry_on_exception(e): _retry = isinstance(e, (requests.ConnectTimeout, requests.ReadTimeout)) if not _retry: print(e) exit() return _retry dkw = { 'stop_max_attempt_number': 3, 'wait_random_min': 2000, 'wait_random_max': 6000, 'retry_on_exception': _retry_on_exception } class Freenom: def __init__(self, username, password, **kwargs): """ init params :param username: your username :type username: str :param password: your password :type password: str """ # path setup self._path = os.getcwd() self._cookies_path = os.path.join(os.getcwd(), 'cookies_data') self._data_path = os.path.join(os.getcwd(), 'freenom_data') # user setup self.username = username self.password = password # request setup self.headers = { 'Host': 'my.freenom.com', 'Referer': 'https://my.freenom.com/clientarea.php', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36' } self.session = requests.session() self.session.headers = self.headers self.token = '' # cookies setup cookies = MozillaCookieJar(filename=self._cookies_path) if os.path.isfile(self._cookies_path): cookies.load(self._cookies_path, ignore_discard=True, ignore_expires=True) self.session.cookies = cookies # option setup --dev self.timeout = kwargs.get('timeout', 22) self.saveHtml = kwargs.get('saveHtml', False) self._RequireData() @secure_retry @retry(**dkw) def _request(self, req, url, **kwargs): kwargs = { 'data': kwargs.get('data', {}), 'timeout': kwargs.get('timeout', self.timeout), 'headers': kwargs.get('headers', self.headers) } # send request res = req(url, **kwargs) # is loggedIn? loggedIn = self._parse(res.content.decode(), '//body/@class')[0] if not 'loggedIn' in loggedIn: self.token = self._parse(res.content.decode(), '//input[@name="token"]/@value')[0] self.doLogin() raise requests.ConnectTimeout return res def _saveHtml(self, html_text, filename='res'): if self.saveHtml: with open(f'{self._path}/{filename}.html', 'w', encoding='utf-8') as f: time = f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" f.write(f'') f.write(html_text) def _parse(self, html_text, xpath): try: self._saveHtml(html_text) element = etree.HTML(html_text) return element.xpath(xpath) except Exception as e: print('parse fail:', end=' ') return [] def _getData(self): """get local domain_data""" data = {} try: if not os.path.isfile(self._data_path): self._RequireData() with open(self._data_path, encoding='utf-8') as f: data = json.loads(f.read()) except Exception as e: print(e) return data return data def _RequireData(self): """Cache all domain and domain_id to local""" domains_data = {} url = "https://my.freenom.com/clientarea.php?action=domains" res = self._request(self.session.get, url) # parse html text domains = self._parse(res.text, "//td[@class='second']//text()") href = self._parse(res.text, "//td[@class='seventh']//a/@href") if domains and href: domains = [i.strip() for i in domains[:] if i.strip()] id = [i.split('=')[-1] for i in href[:]] domains_data = dict(zip(domains, id)) # Save as local file f = open(self._data_path, 'w', encoding='utf-8') f.write(json.dumps(domains_data)) f.close() return domains_data def _getRecordList(self, domain, domainid): data = [] url = 'https://my.freenom.com/clientarea.php?managedns=%s&domainid=%s' % (domain, domainid) res = self._request(self.session.get, url) recordslist = self._parse(res.content.decode(), '//*[@id="recordslistform"]/table/tbody/tr') if recordslist: for record in recordslist: tmp_list = [] name = record.xpath('./td[@class="name_column"]//input[@type="text"]/@value')[0] type = record.xpath('./td[@class="type_column"]//text()')[0] ttl = record.xpath('./td[@class="ttl_column"]//input[@type="text"]/@value')[0] target = record.xpath('./td[@class="value_column"]//input[@type="text"]/@value')[0] tmp_list.append(name) tmp_list.append(type) tmp_list.append(ttl) tmp_list.append(target) data.append(tmp_list) return data def _isAddRecord(self, records, name): # No records if not records: return True # no name in records for record in records: if name == record[0]: return False return True def _showDnsResult(self, html_text, xpath_list): # show dns result if not html_text: print('no html text') return for xpath in xpath_list: dns_res = self._parse(html_text, xpath) if dns_res: print(dns_res[0]) return print('cannot find dns result') return @secure_retry @retry(**dkw) def doLogin(self, username=None, password=None): print('doLogin:', end=' ') url = 'https://my.freenom.com/dologin.php' form_data = { 'token': self.token if self.token else '', 'username': username if username else self.username, 'password': password if password else self.password } # send request and save cookies as local res = self.session.post(url, data=form_data) if res.url.find('incorrect=true') != -1: print(self._parse(res.content.decode(), '//div[contains(@class,"error-message")]/p/text()')[0]) exit() else: self.session.cookies.save(ignore_discard=True, ignore_expires=True) print('Login successfully.') def setRecord(self, domain, name, type, target, ttl='3600'): """ add or modify record :param domain: :param name: :param type: :param target: <0.0.0.0> :param kwargs: ttl|... :type domain: str :type name: str :type type: str :type target: str :type ttl: str """ data = self._getData() print('setRecord:', end=' ') if not domain in data: print('No data found for this domain') return # init params url = 'https://my.freenom.com/clientarea.php?managedns=%s&domainid=%s' name = name.upper() type = type.upper() ttl = str(ttl) target = str(target) # add or modify? records = self._getRecordList(domain, data.get(domain)) if self._isAddRecord(records, name): # add form_data = { 'token': '', 'dnsaction': 'add', 'addrecord[0][name]': name, 'addrecord[0][type]': type, 'addrecord[0][ttl]': ttl, 'addrecord[0][value]': target, } else: # modify form_data = { 'token': '', 'dnsaction': 'modify', } for i in range(len(records)): if type == records[i][1]: if name == records[i][0]: records[i][3] = target form_data[f'records[{i}][name]'] = records[i][0] form_data[f'records[{i}][type]'] = records[i][1] form_data[f'records[{i}][ttl]'] = records[i][2] form_data[f'records[{i}][value]'] = records[i][3] # send request res = self._request(self.session.post, url % (domain, data.get(domain)), data=form_data) # show dns result self._showDnsResult(res.content.decode(), ['//div[@class="recordslist"]/ul/li/text()', '//section[@class="domainContent"]//p/text()']) def delRecord(self, domain, name, type='', target='', ttl='3600'): """ del record :param domain: :param name: :param type: :param target: <0.0.0.0> :param kwargs: ttl|... :type domain: str :type name: str :type type: str :type target: str :type ttl: str """ data = self._getData() print('delRecord:', end=' ') if not domain in data: print('No data found for this domain') return # init params url = 'https://my.freenom.com/clientarea.php?' \ 'managedns={}&' \ 'records={}&' \ 'dnsaction=delete&' \ 'name={}&' \ 'value={}&' \ 'ttl={}&' \ 'domainid={}' name = name.upper() type = type.upper() ttl = str(ttl) target = str(target) domainid = data.get(domain, '') records = self._getRecordList(domain, domainid) if records: for record in records: if name == record[0]: type = record[1] ttl = record[2] target = record[3] # send request res = self._request(self.session.get, url.format(domain, type, name, target, ttl, domainid)) # show dns result # show dns result self._showDnsResult(res.content.decode(), ['//div[@class="recordslist"]/ul/li/text()', '//section[@class="domainContent"]//p/text()']) else: print('no records to delete') def showRecords(self, domain): data = self._getData() if not domain in data: print('No data found for this domain') return records = self._getRecordList(domain, data.get(domain, '')) print(f'{domain:-^38}') if records: for record in records: print(record) else: print(f'{"No records to display":-^38}') @secure_retry @retry(**dkw) def getPublicIP(self, url='https://api.ipify.org'): print('PublicIP:', end=' ') res = requests.get(url, timeout=self.timeout) pub_ip = res.content.decode() print(pub_ip) return pub_ip freenom-0.0.2/freenom.egg-info/0000755000175000017500000000000013651115351015672 5ustar shmshm00000000000000freenom-0.0.2/freenom.egg-info/PKG-INFO0000644000175000017500000000400513651115351016766 0ustar shmshm00000000000000Metadata-Version: 2.1 Name: freenom Version: 0.0.2 Summary: Freenom DNS API Home-page: https://github.com/Shm013/freenom-dns Author: Nikolay Shamanovich Author-email: shm013@yandex.ru License: UNKNOWN Description: Freenom-dns Script ======================== An unofficial python implementation for managing freenom.com dns records. ## Freenom Freenom is the world's first and only free domain provider. ## Install ``` pip install git+https://github.com/Shm013/freenom-dns.git ``` ## How to use ```python from freenom import Freenom if __name__ == '__main__': freenom = Freenom('your username', 'your password') ################################################### pub_ip = freenom.getPublicIP() # add or modify a record freenom.setRecord('your domain', '', 'a', pub_ip) freenom.setRecord('your domain', 'www', 'a', pub_ip) freenom.setRecord('your domain', 'test', 'a', pub_ip) # delete a record freenom.delRecord('your domain', 'test') # show all records with domain freenom.showRecords('your domain') ``` ## print results ``` doLogin: Login successfully. PublicIP: xxx.xxx.xxx.xxx setRecord: There were no changes setRecord: There were no changes setRecord: Record added successfully delRecord: Record deleted successfully --------------your domain-------------- ['', 'A', '3600', 'xxx.xxx.xxx.xxx'] ['WWW', 'A', '3600', 'xxx.xxx.xxx.xxx'] ``` ## License [MIT](https://github.com/PunkLee2py/freenom-dns/blob/master/LICENSE) Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Requires-Python: >=3.6 Description-Content-Type: text/markdown freenom-0.0.2/freenom.egg-info/SOURCES.txt0000644000175000017500000000033313651115351017555 0ustar shmshm00000000000000.gitignore LICENSE README.md setup.py test.py freenom/__init__.py freenom.egg-info/PKG-INFO freenom.egg-info/SOURCES.txt freenom.egg-info/dependency_links.txt freenom.egg-info/requires.txt freenom.egg-info/top_level.txtfreenom-0.0.2/freenom.egg-info/dependency_links.txt0000644000175000017500000000000113651115351021740 0ustar shmshm00000000000000 freenom-0.0.2/freenom.egg-info/requires.txt0000644000175000017500000000005513651115351020272 0ustar shmshm00000000000000requests>=2.23.0 lxml>=4.5.0 retrying>=1.3.3 freenom-0.0.2/freenom.egg-info/top_level.txt0000644000175000017500000000001013651115351020413 0ustar shmshm00000000000000freenom freenom-0.0.2/.gitignore0000644000175000017500000000012713651114746014544 0ustar shmshm00000000000000.idea __pycache__ venv/ cookies_data freenom_data *.sw? build/ dist/ freenom.egg-info/ freenom-0.0.2/LICENSE0000644000175000017500000000205313650605425013557 0ustar shmshm00000000000000MIT License Copyright (c) 2020 PunkLee2py Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. freenom-0.0.2/README.md0000644000175000017500000000235313651027116014030 0ustar shmshm00000000000000Freenom-dns Script ======================== An unofficial python implementation for managing freenom.com dns records. ## Freenom Freenom is the world's first and only free domain provider. ## Install ``` pip install git+https://github.com/Shm013/freenom-dns.git ``` ## How to use ```python from freenom import Freenom if __name__ == '__main__': freenom = Freenom('your username', 'your password') ################################################### pub_ip = freenom.getPublicIP() # add or modify a record freenom.setRecord('your domain', '', 'a', pub_ip) freenom.setRecord('your domain', 'www', 'a', pub_ip) freenom.setRecord('your domain', 'test', 'a', pub_ip) # delete a record freenom.delRecord('your domain', 'test') # show all records with domain freenom.showRecords('your domain') ``` ## print results ``` doLogin: Login successfully. PublicIP: xxx.xxx.xxx.xxx setRecord: There were no changes setRecord: There were no changes setRecord: Record added successfully delRecord: Record deleted successfully --------------your domain-------------- ['', 'A', '3600', 'xxx.xxx.xxx.xxx'] ['WWW', 'A', '3600', 'xxx.xxx.xxx.xxx'] ``` ## License [MIT](https://github.com/PunkLee2py/freenom-dns/blob/master/LICENSE) freenom-0.0.2/setup.py0000644000175000017500000000143213651115321014254 0ustar shmshm00000000000000import setuptools with open("README.md", "r") as fh: long_description = fh.read() install_requires = [ "requests>=2.23.0", "lxml>=4.5.0", "retrying>=1.3.3", ] setuptools.setup( name="freenom", # Replace with your own username version="0.0.2", author="Nikolay Shamanovich", author_email="shm013@yandex.ru", description="Freenom DNS API", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/Shm013/freenom-dns", packages=setuptools.find_packages(), classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ], python_requires='>=3.6', install_requires=install_requires, ) freenom-0.0.2/test.py0000644000175000017500000000110113650605425014074 0ustar shmshm00000000000000# -*- coding: utf-8 -*- from freenom import Freenom if __name__ == '__main__': freenom = Freenom('18683833822@163.com', '496709219') ################################################### pub_ip = freenom.getPublicIP() # add or modify a record freenom.setRecord('wagger2.ga', '', 'a', pub_ip) freenom.setRecord('wagger2.ga', 'www', 'a', pub_ip) freenom.setRecord('wagger2.ga', 'asd', 'a', '192.168.123.111') # delete a record freenom.delRecord('wagger2.ga', 'asd') # show all records with domain freenom.showRecords('wagger2.ga') freenom-0.0.2/PKG-INFO0000644000175000017500000000400513651115351013641 0ustar shmshm00000000000000Metadata-Version: 2.1 Name: freenom Version: 0.0.2 Summary: Freenom DNS API Home-page: https://github.com/Shm013/freenom-dns Author: Nikolay Shamanovich Author-email: shm013@yandex.ru License: UNKNOWN Description: Freenom-dns Script ======================== An unofficial python implementation for managing freenom.com dns records. ## Freenom Freenom is the world's first and only free domain provider. ## Install ``` pip install git+https://github.com/Shm013/freenom-dns.git ``` ## How to use ```python from freenom import Freenom if __name__ == '__main__': freenom = Freenom('your username', 'your password') ################################################### pub_ip = freenom.getPublicIP() # add or modify a record freenom.setRecord('your domain', '', 'a', pub_ip) freenom.setRecord('your domain', 'www', 'a', pub_ip) freenom.setRecord('your domain', 'test', 'a', pub_ip) # delete a record freenom.delRecord('your domain', 'test') # show all records with domain freenom.showRecords('your domain') ``` ## print results ``` doLogin: Login successfully. PublicIP: xxx.xxx.xxx.xxx setRecord: There were no changes setRecord: There were no changes setRecord: Record added successfully delRecord: Record deleted successfully --------------your domain-------------- ['', 'A', '3600', 'xxx.xxx.xxx.xxx'] ['WWW', 'A', '3600', 'xxx.xxx.xxx.xxx'] ``` ## License [MIT](https://github.com/PunkLee2py/freenom-dns/blob/master/LICENSE) Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Requires-Python: >=3.6 Description-Content-Type: text/markdown freenom-0.0.2/setup.cfg0000644000175000017500000000004613651115351014366 0ustar shmshm00000000000000[egg_info] tag_build = tag_date = 0