Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"mrmlnc.vscode-apache",
"ms-azuretools.vscode-docker",
"eamodio.gitlens",
"GitHub.copilot"
"GitHub.copilot",
"bmewburn.vscode-intelephense-client"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "zsh",
Expand Down
13 changes: 12 additions & 1 deletion .devcontainer/supporting_files/scripts/post-create.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,18 @@ source ~/.zshrc
pip install --upgrade pip
pip install --upgrade setuptools
pip -V
#pip install -r requirements.txt

# Install pip-tools
pip install pip-tools

# Generate requirements.txt from pyproject.toml
pip-compile pyproject.toml

# Install dependencies from requirements.txt
pip install -r requirements.txt

# Install the local centralnicreseller module as an editable package
pip install -e .

echo "=> Generating Symlinks for Zsh History and Git config"
# Create symlink for gitconfig and zsh history file
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,5 @@ venv.bak/

# node_modules
node_modules

requirements.txt
48 changes: 33 additions & 15 deletions centralnicreseller/apiconnector/apiclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

from centralnicreseller.apiconnector.logger import Logger
from centralnicreseller.apiconnector.response import Response
from centralnicreseller.apiconnector.responsetemplatemanager import ResponseTemplateManager as RTM
from centralnicreseller.apiconnector.responsetemplatemanager import (
ResponseTemplateManager as RTM,
)
from centralnicreseller.apiconnector.socketconfig import SocketConfig
from centralnicreseller.apiconnector.idnaconverter import IDNAConverter
from urllib.parse import quote, unquote, urlparse, urlencode
Expand Down Expand Up @@ -124,8 +126,9 @@ def getPOSTData(self, cmd, secured=False):
tmp = cmd.rstrip("\n")
else:
tmp = "\n".join(
"{}={}".format(key, re.sub(r'[\r\n]', '', str(cmd[key])))
for key in sorted(cmd.keys()) if cmd[key] is not None
"{}={}".format(key, re.sub(r"[\r\n]", "", str(cmd[key])))
for key in sorted(cmd.keys())
if cmd[key] is not None
)

if secured:
Expand All @@ -134,7 +137,7 @@ def getPOSTData(self, cmd, secured=False):
if tmp:
return f"{data}{quote('s_command')}={quote(tmp)}"
else:
return data if not data.endswith('&') else data.rstrip('&')
return data if not data.endswith("&") else data.rstrip("&")

def getURL(self):
"""
Expand Down Expand Up @@ -203,7 +206,12 @@ def reuseSession(self, session):
Use existing configuration out of session
to rebuild and reuse connection settings
"""
if not session or "socketcfg" not in session or "login" not in session["socketcfg"] or "session" not in session["socketcfg"]:
if (
not session
or "socketcfg" not in session
or "login" not in session["socketcfg"]
or "session" not in session["socketcfg"]
):
return self
self.setCredentials(session["socketcfg"]["login"])
self.__socketConfig.setSession(session["socketcfg"]["session"])
Expand All @@ -217,7 +225,7 @@ def setURL(self, value):
return self

def setPersistent(self):
"""echo
"""echo
Set persistent connection to be used for API communication
"""
self.__socketConfig.setPersistent()
Expand All @@ -231,24 +239,29 @@ def setCredentials(self, uid, pw=""):
self.__socketConfig.setPassword(pw)
return self

def setRoleCredentials(self, uid, role, pw = ""):
def setRoleCredentials(self, uid, role, pw=""):
"""
Set Credentials to be used for API communication
"""
if role == "":
return self.setCredentials(uid, pw)
return self.setCredentials(("{0}{1}{2}").format(uid, self.__roleSeparator, role), pw)
return self.setCredentials(
("{0}{1}{2}").format(uid, self.__roleSeparator, role), pw
)

def login(self):
"""
Perform API login to start session-based communication
"""
self.setPersistent()
rr = self.request([], False)
self.__socketConfig.setSession(None) # clean up all session related data
self.__socketConfig.setSession(None) # clean up all session related data
if rr.isSuccess():
col = rr.getColumn("SESSIONID")
self.__socketConfig.setSession(col.getData()[0] if (col is not None) else None)
print("session id", col)
self.__socketConfig.setSession(
col.getData()[0] if (col is not None) else None
)
return rr

def logout(self):
Expand All @@ -261,7 +274,7 @@ def logout(self):
}
)
if rr.isSuccess():
self.__socketConfig.setSession(None) # clean up all session related data
self.__socketConfig.setSession(None) # clean up all session related data
return rr

def request(self, cmd=[], setUserView=True):
Expand Down Expand Up @@ -407,16 +420,21 @@ def __autoIDNConvert(self, cmd):
"""
key_pattern = re.compile(r"(?i)^(NAMESERVER|NS|DNSZONE)([0-9]*)$")
obj_class_pattern = re.compile(
r"(?i)^(DOMAIN(APPLICATION|BLOCKING)?|NAMESERVER|NS|DNSZONE)$")
r"(?i)^(DOMAIN(APPLICATION|BLOCKING)?|NAMESERVER|NS|DNSZONE)$"
)
ascii_pattern = re.compile(r"^[A-Za-z0-9.\-]+$")

to_convert = []
idxs = []

for key, val in cmd.items():
if ((key_pattern.match(key) or
(key.upper() == "OBJECTID" and obj_class_pattern.match(cmd.get("OBJECTCLASS", ""))))
and not ascii_pattern.match(val)):
if (
key_pattern.match(key)
or (
key.upper() == "OBJECTID"
and obj_class_pattern.match(cmd.get("OBJECTCLASS", ""))
)
) and not ascii_pattern.match(val):
to_convert.append(val)
idxs.append(key)

Expand Down
1 change: 1 addition & 0 deletions centralnicreseller/apiconnector/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
:license: MIT, see LICENSE for more details.
"""


class Column(object):
"""
The Column class covers all you need to access column data of a Backend API response.
Expand Down
8 changes: 6 additions & 2 deletions centralnicreseller/apiconnector/idnaconverter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from centralnicreseller.apiconnector.idnaprocessor import IDNAProcessor


class IDNAConverter:
def __init__(self, idn=None, pc=None, idn_list=None, pc_list=None):
self.idn = idn
Expand All @@ -23,7 +25,9 @@ def convert_list(domain_names, use_transitional=None):
for domain_name in domain_names:
try:
pc_results.append(IDNAProcessor.to_ascii(domain_name, use_transitional))
idn_results.append(IDNAProcessor.to_unicode(domain_name, use_transitional))
idn_results.append(
IDNAProcessor.to_unicode(domain_name, use_transitional)
)
except Exception:
pc_results.append(domain_name)
idn_results.append(domain_name)
Expand All @@ -40,4 +44,4 @@ def get_idn_list(self):
return self.idn_list

def get_pc_list(self):
return self.pc_list
return self.pc_list
5 changes: 3 additions & 2 deletions centralnicreseller/apiconnector/idnaprocessor.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import idna
import re


class IDNAProcessor:
NON_TRANSITIONAL_TLDS = re.compile(
r"\.(?:art|be|ca|de|swiss|fr|pm|re|tf|wf|yt)\.?$"
)

@staticmethod
def is_transitional_processing(domain_name: str) -> bool:
"""
Expand All @@ -20,7 +21,7 @@ def to_ascii(domain_name, use_transitional=None):
try:
if use_transitional:
domain_name = idna.uts46_remap(domain_name, transitional=True)
return idna.encode(domain_name).decode('ascii')
return idna.encode(domain_name).decode("ascii")
except idna.IDNAError as e:
raise ValueError(f"Unable to translate {domain_name} to ASCII: {e}")

Expand Down
9 changes: 6 additions & 3 deletions centralnicreseller/apiconnector/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,7 @@ def getCurrentRecord(self):
Get Record of current record index
"""
return (
self.__records[self.__recordIndex] if (
self.__hasCurrentRecord()) else None
self.__records[self.__recordIndex] if (self.__hasCurrentRecord()) else None
)

def getFirstRecordIndex(self):
Expand Down Expand Up @@ -353,7 +352,11 @@ def isPending(self):
"""
# Check if the COMMAND is AddDomain (case-insensitive)
cmd = self.getCommand()
if cmd is None or not cmd.get("COMMAND") or cmd["COMMAND"].lower() != "adddomain":
if (
cmd is None
or not cmd.get("COMMAND")
or cmd["COMMAND"].lower() != "adddomain"
):
return False

# Retrieve the STATUS column and check if its data equals REQUESTED (case-insensitive)
Expand Down
2 changes: 1 addition & 1 deletion centralnicreseller/apiconnector/responseparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ def parse(raw):
r["PROPERTY"][prop].append(value)
else:
r[attr.upper()] = value
return r
return r
5 changes: 2 additions & 3 deletions centralnicreseller/apiconnector/responsetemplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ def __init__(self, response=""):
self._raw = response
if (response == "") or (response is None):
descr = "Empty API response. Probably unreachable API end point {CONNECTION_URL}"
self._raw = "[RESPONSE]\r\nCODE=423\r\nDESCRIPTION=%s\r\nEOF\r\n" % (
descr)
self._raw = "[RESPONSE]\r\nCODE=423\r\nDESCRIPTION=%s\r\nEOF\r\n" % (descr)

# try/except to support old versions of python (python2.5)
try:
Expand Down Expand Up @@ -102,4 +101,4 @@ def isTmpError(self):
"""
Check if current API response represents a temporary error case (4xx)
"""
return self.__hash["CODE"][0] == "4"
return self.__hash["CODE"][0] == "4"
32 changes: 16 additions & 16 deletions htmlcov/class_index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading