diff --git a/CHANGELOG.md b/CHANGELOG.md index 5788b8a..5054302 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.9.22 (2025-10-23) + +### Changes + +- Add an option for skipping TLS verification. +- Allow redirects for HEAD and POST requests. + ## 0.9.21 (2025-10-16) ### Changes diff --git a/bin/mujin_webstackclientpy_applyconfig.py b/bin/mujin_webstackclientpy_applyconfig.py index f844554..b052cd3 100755 --- a/bin/mujin_webstackclientpy_applyconfig.py +++ b/bin/mujin_webstackclientpy_applyconfig.py @@ -239,6 +239,7 @@ def _RunMain(): parser.add_argument('--force', action='store_true', dest='force', default=False, help='apply without confirmation [default=%(default)s]') parser.add_argument('--dryrun', action='store_true', dest='dryrun', default=False, help='shows differences and quit [default=%(default)s]') parser.add_argument('--oneline', action='store_true', dest='oneline', default=False, help='shows each difference in one line [default=%(default)s]') + parser.add_argument('--tlsSkipVerify', type=bool, default=True, help='Whether to skip TLS verification (default: %(default)s)') options = parser.parse_args() # configure logging @@ -265,7 +266,7 @@ def _RunMain(): # construct client if options.controller: - webstackclient = WebstackClient('http://%s' % options.controller, options.username, options.password) + webstackclient = WebstackClient('http://%s' % options.controller, options.username, options.password, tlsSkipVerify=options.tlsSkipVerify) webstackclient.Ping() config = webstackclient.GetConfig() target = webstackclient.controllerIp diff --git a/bin/mujin_webstackclientpy_downloaddata.py b/bin/mujin_webstackclientpy_downloaddata.py index 0801f64..11baca9 100755 --- a/bin/mujin_webstackclientpy_downloaddata.py +++ b/bin/mujin_webstackclientpy_downloaddata.py @@ -27,6 +27,7 @@ def _ParseArguments(): parser.add_argument('--password', type=str, default='mujin', help='Password to login with (default: %(default)s)') parser.add_argument('--backupSceneFormat', type=str, default=None, help='The scene format to use in backup files, one of "msgpack", "json", or "yaml" (default: %(default)s)') parser.add_argument('--timeout', type=float, default=600, help='Timeout in seconds (default: %(default)s)') + parser.add_argument('--tlsSkipVerify', type=bool, default=True, help='Whether to skip TLS verification (default: %(default)s)') return parser.parse_args() @@ -92,7 +93,7 @@ def _Main(): options = _ParseArguments() _ConfigureLogging(options.loglevel) - webClient = _CreateWebstackClient(options.url, options.username, options.password) + webClient = _CreateWebstackClient(options.url, options.username, options.password, tlsSkipVerify=options.tlsSkipVerify) sceneList = _GetScenes(webClient) downloadDirectory = _DownloadBackup(webClient, sceneList, options.backupSceneFormat, timeout=options.timeout) print(downloadDirectory) # other scripts can read stdout and learn the directory path diff --git a/bin/mujin_webstackclientpy_runshell.py b/bin/mujin_webstackclientpy_runshell.py index 60ad660..56727df 100755 --- a/bin/mujin_webstackclientpy_runshell.py +++ b/bin/mujin_webstackclientpy_runshell.py @@ -17,6 +17,7 @@ def _ParseArguments(): parser.add_argument('--url', type=str, default='http://localhost', help='URL of the controller (default: %(default)s)') parser.add_argument('--username', type=str, default='mujin', help='Username to login with (default: %(default)s)') parser.add_argument('--password', type=str, default='mujin', help='Password to login with (default: %(default)s)') + parser.add_argument('--tlsSkipVerify', type=bool, default=True, help='Whether to skip TLS verification (default: %(default)s)') return parser.parse_args() @@ -33,7 +34,7 @@ def _Main(): options = _ParseArguments() _ConfigureLogging(options.loglevel) - self = WebstackClient(options.url, options.username, options.password) + self = WebstackClient(options.url, options.username, options.password, tlsSkipVerify=options.tlsSkipVerify) # launch interactive shell from IPython.terminal import embed diff --git a/python/mujinwebstackclient/controllerwebclientraw.py b/python/mujinwebstackclient/controllerwebclientraw.py index 0a861ba..aa50f6b 100644 --- a/python/mujinwebstackclient/controllerwebclientraw.py +++ b/python/mujinwebstackclient/controllerwebclientraw.py @@ -169,6 +169,7 @@ def __init__( userAgent: Optional[str] = None, additionalHeaders: Optional[Dict[str, str]] = None, unixEndpoint: Optional[str] = None, + tlsSkipVerify: bool = False, warnOnUseFromDifferentThreads: bool = False, ) -> None: self._baseurl = baseurl @@ -182,6 +183,7 @@ def __init__( # Create session self._session = requests.Session() + self._session.verify = not tlsSkipVerify # Use basic auth by default, use JWT if available self._session.auth = JSONWebTokenAuth(self._username, self._password) @@ -278,7 +280,7 @@ def Request( if 'allow_redirects' not in kwargs: # by default, disallow redirect since DELETE with redirection is too dangerous - kwargs['allow_redirects'] = method in ('GET',) + kwargs['allow_redirects'] = method in ('HEAD', 'GET', 'POST') if self._threadName is not None: currentName = threading.current_thread().name diff --git a/python/mujinwebstackclient/version.py b/python/mujinwebstackclient/version.py index 18d7d8f..bf079b9 100644 --- a/python/mujinwebstackclient/version.py +++ b/python/mujinwebstackclient/version.py @@ -1,3 +1,3 @@ -__version__ = '0.9.21' +__version__ = '0.9.22' # Do not forget to update CHANGELOG.md diff --git a/python/mujinwebstackclient/webstackclient.py b/python/mujinwebstackclient/webstackclient.py index c44ecff..b4ac250 100644 --- a/python/mujinwebstackclient/webstackclient.py +++ b/python/mujinwebstackclient/webstackclient.py @@ -112,7 +112,7 @@ def offset(self): _webclient = None _userinfo = None # A dict storing user info, like locale - controllerurl = '' # URl to controller + controllerurl = '' # URL to controller controllerusername = '' # Username to login with controllerpassword = '' # Password to login with @@ -128,6 +128,7 @@ def __init__( userAgent=None, additionalHeaders=None, unixEndpoint=None, + tlsSkipVerify: bool = True, warnOnUseFromDifferentThreads: bool = False, ): """Logs into the Mujin controller. @@ -139,6 +140,7 @@ def __init__( userAgent (str): User agent to be sent on each request additionalHeaders (dict): Additional HTTP headers to be included in requests unixEndpoint (str): Unix socket endpoint for communicating with HTTP server over unix socket + tlsSkipVerify (bool): Whether to skip TLS verification warnOnUseFromDifferentThreads (bool): Whether to warn callers if the client is used from different threads. Defaults to not warning since checking the thread name on each call may significantly degrade performance. """ @@ -175,6 +177,7 @@ def __init__( userAgent=userAgent, additionalHeaders=additionalHeaders, unixEndpoint=unixEndpoint, + tlsSkipVerify=tlsSkipVerify, warnOnUseFromDifferentThreads=warnOnUseFromDifferentThreads, )