Thu, 11 Jul 2024 14:21:34 +0200
MicroPython
- Updated the list of known CircuitPython boards for CPy 9.1.0.
- Updated the list of known UF2 capable boards.
# -*- coding: utf-8 -*- # Copyright (c) 2012 - 2024 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing an extension to the Python FTP class to support FTP proxies. """ import enum import ftplib # secok from socket import _GLOBAL_DEFAULT_TIMEOUT class EricFtpProxyError(ftplib.Error): """ Class to signal an error related to proxy configuration. The error message starts with a three digit error code followed by a space and the error string. Supported error codes are: <ul> <li>910: proxy error; the second number gives the category of the proxy error. The original response from the proxy is appended in the next line.</li> <li>930: proxy error; the second number gives the category of the proxy error. The original response from the proxy is appended in the next line.</li> <li>940: proxy error; the second number gives the category of the proxy error. The original response from the proxy is appended in the next line.</li> <li>950: proxy error; the second number gives the category of the proxy error. The original response from the proxy is appended in the next line.</li> <li>990: proxy usage is enabled but no proxy host given</li> <li>991: proxy usage is enabled but no proxy user given</li> <li>992: proxy usage is enabled but no proxy password given</li> </ul> """ pass class EricFtpProxyType(enum.Enum): """ Class defining the supported FTP proxy types. """ NO_PROXY = 0 # no proxy NON_AUTHORIZING = 1 # non authorizing proxy USER_SERVER = 2 # proxy login first, than user@remote.host SITE = 3 # proxy login first, than use SITE command OPEN = 4 # proxy login first, than use OPEN command USER_PROXYUSER_SERVER = 5 # one login for both PROXYUSER_SERVER = 6 # proxy login with remote host given, than normal remote login AUTH_RESP = 7 # authenticate to proxy with AUTH and RESP commands BLUECOAT = 8 # bluecoat proxy class EricFtp(ftplib.FTP): """ Class implementing an extension to the Python FTP class to support FTP proxies. """ def __init__( # secok self, host="", user="", password="", acct="", proxyType=EricFtpProxyType.NO_PROXY, proxyHost="", proxyPort=ftplib.FTP_PORT, proxyUser="", proxyPassword="", proxyAccount="", timeout=_GLOBAL_DEFAULT_TIMEOUT, ): """ Constructor @param host name of the FTP host @type str @param user user name for login to FTP host @type str @param password password for login to FTP host @type str @param acct account for login to FTP host @type str @param proxyType type of the FTP proxy @type EricFtpProxyType @param proxyHost name of the FTP proxy @type str @param proxyPort port of the FTP proxy @type int @param proxyUser user name for login to the proxy @type str @param proxyPassword password for login to the proxy @type str @param proxyAccount accounting info for the proxy @type str @param timeout timeout in seconds for blocking operations @type int """ super().__init__() self.__timeout = timeout self.__proxyType = proxyType self.__proxyHost = proxyHost self.__proxyPort = proxyPort self.__proxyUser = proxyUser self.__proxyPassword = proxyPassword self.__proxyAccount = proxyAccount self.__host = host self.__port = ftplib.FTP_PORT if host: self.connect(host) if user: self.login(user, password, acct) def setProxy( self, proxyType=EricFtpProxyType.NO_PROXY, proxyHost="", proxyPort=ftplib.FTP_PORT, proxyUser="", proxyPassword="", proxyAccount="", ): """ Public method to set the proxy configuration. @param proxyType type of the FTP proxy @type EricFtpProxyType @param proxyHost name of the FTP proxy @type str @param proxyPort port of the FTP proxy @type int @param proxyUser user name for login to the proxy @type str @param proxyPassword password for login to the proxy @type str @param proxyAccount accounting info for the proxy @type str """ self.__proxyType = proxyType self.__proxyHost = proxyHost self.__proxyPort = proxyPort self.__proxyUser = proxyUser self.__proxyPassword = proxyPassword self.__proxyAccount = proxyAccount def setProxyAuthentication(self, proxyUser="", proxyPassword="", proxyAccount=""): """ Public method to set the proxy authentication info. @param proxyUser user name for login to the proxy @type str @param proxyPassword password for login to the proxy @type str @param proxyAccount accounting info for the proxy @type str """ self.__proxyUser = proxyUser self.__proxyPassword = proxyPassword self.__proxyAccount = proxyAccount def connect(self, host="", port=0, timeout=-999): """ Public method to connect to the given FTP server. This extended method connects to the proxy instead of the given host, if a proxy is to be used. It throws an exception, if the proxy data is incomplete. @param host name of the FTP host @type str @param port port of the FTP host @type int @param timeout timeout in seconds for blocking operations @type int @return welcome message of the server @rtype str @exception EricFtpProxyError raised to indicate a proxy related issue """ if host: self.__host = host if port: self.__port = port if timeout != -999: self.__timeout = timeout if self.__proxyType != EricFtpProxyType.NO_PROXY: if not self.__proxyHost: raise EricFtpProxyError( "990 Proxy usage requested, but no proxy host given." ) return super().connect(self.__proxyHost, self.__proxyPort, self.__timeout) else: return super().connect(self.__host, self.__port, self.__timeout) def login(self, user="", password="", acct=""): # secok """ Public method to login to the FTP server. This extended method respects the FTP proxy configuration. There are many different FTP proxy products available. But unfortunately there is no standard for how o traverse a FTP proxy. The lis below shows the sequence of commands used. <table> <tr><td>user</td><td>Username for remote host</td></tr> <tr><td>pass</td><td>Password for remote host</td></tr> <tr><td>pruser</td><td>Username for FTP proxy</td></tr> <tr><td>prpass</td><td>Password for FTP proxy</td></tr> <tr><td>remote.host</td><td>Hostname of the remote FTP server</td> </tr> </table> <dl> <dt>EricFtpProxyType.NO_PROXY:</dt> <dd> USER user<br/> PASS pass </dd> <dt>EricFtpProxyType.NON_AUTHORIZING:</dt> <dd> USER user@remote.host<br/> PASS pass </dd> <dt>EricFtpProxyType.USER_SERVER:</dt> <dd> USER pruser<br/> PASS prpass<br/> USER user@remote.host<br/> PASS pass </dd> <dt>EricFtpProxyType.SITE:</dt> <dd> USER pruser<br/> PASS prpass<br/> SITE remote.site<br/> USER user<br/> PASS pass </dd> <dt>EricFtpProxyType.OPEN:</dt> <dd> USER pruser<br/> PASS prpass<br/> OPEN remote.site<br/> USER user<br/> PASS pass </dd> <dt>EricFtpProxyType.USER_PROXYUSER_SERVER:</dt> <dd> USER user@pruser@remote.host<br/> PASS pass@prpass </dd> <dt>EricFtpProxyType.PROXYUSER_SERVER:</dt> <dd> USER pruser@remote.host<br/> PASS prpass<br/> USER user<br/> PASS pass </dd> <dt>EricFtpProxyType.AUTH_RESP:</dt> <dd> USER user@remote.host<br/> PASS pass<br/> AUTH pruser<br/> RESP prpass </dd> <dt>EricFtpProxyType.BLUECOAT:</dt> <dd> USER user@remote.host pruser<br/> PASS pass<br/> ACCT prpass </dd> </dl> @param user username for the remote host @type str @param password password for the remote host @type str @param acct accounting information for the remote host @type str @return response sent by the remote host @rtype str @exception EricFtpProxyError raised to indicate a proxy related issue @exception ftplib.error_reply raised to indicate an FTP error reply """ if not user: user = "anonymous" if not password: # make sure it is a string password = "" # secok if not acct: # make sure it is a string acct = "" if user == "anonymous" and password in {"", "-"}: password += "anonymous@" if self.__proxyType != EricFtpProxyType.NO_PROXY: if self.__proxyType != EricFtpProxyType.NON_AUTHORIZING: # check, if a valid proxy configuration is known if not self.__proxyUser: raise EricFtpProxyError( "991 Proxy usage requested, but no proxy user given" ) if not self.__proxyPassword: raise EricFtpProxyError( "992 Proxy usage requested, but no proxy password given" ) if self.__proxyType in [ EricFtpProxyType.NON_AUTHORIZING, EricFtpProxyType.AUTH_RESP, EricFtpProxyType.BLUECOAT, ]: user += "@" + self.__host if self.__proxyType == EricFtpProxyType.BLUECOAT: user += " " + self.__proxyUser acct = self.__proxyPassword elif self.__proxyType == EricFtpProxyType.USER_PROXYUSER_SERVER: user = "{0}@{1}@{2}".format(user, self.__proxyUser, self.__host) password = "{0}@{1}".format(password, self.__proxyPassword) else: pruser = self.__proxyUser if self.__proxyType == EricFtpProxyType.USER_SERVER: user += "@" + self.__host elif self.__proxyType == EricFtpProxyType.PROXYUSER_SERVER: pruser += "@" + self.__host # authenticate to the proxy first presp = self.sendcmd("USER " + pruser) if presp[0] == "3": presp = self.sendcmd("PASS " + self.__proxyPassword) if presp[0] == "3" and self.__proxyAccount: presp = self.sendcmd("ACCT " + self.__proxyAccount) if presp[0] != "2": raise EricFtpProxyError( "9{0}0 Error authorizing at proxy\n{1}".format(presp[0], presp) ) if self.__proxyType == EricFtpProxyType.SITE: # send SITE command presp = self.sendcmd("SITE " + self.__host) if presp[0] != "2": raise EricFtpProxyError( "9{0}0 Error sending SITE command\n{1}".format( presp[0], presp ) ) elif self.__proxyType == EricFtpProxyType.OPEN: # send OPEN command presp = self.sendcmd("OPEN " + self.__host) if presp[0] != "2": raise EricFtpProxyError( "9{0}0 Error sending OPEN command\n{1}".format( presp[0], presp ) ) # authenticate to the remote host or combined to proxy and remote host resp = self.sendcmd("USER " + user) if resp[0] == "3": resp = self.sendcmd("PASS " + password) if resp[0] == "3": resp = self.sendcmd("ACCT " + acct) if resp[0] != "2": raise ftplib.error_reply(resp) # secok if self.__proxyType == EricFtpProxyType.AUTH_RESP: # authorize to the FTP proxy presp = self.sendcmd("AUTH " + self.__proxyUser) if presp[0] == "3": presp = self.sendcmd("RESP " + self.__proxyPassword) if presp[0] != "2": raise EricFtpProxyError( "9{0}0 Error authorizing at proxy\n{1}".format(presp[0], presp) ) return resp