fix bitrot in util/zotsh
This commit is contained in:
parent
6f8c977e73
commit
beeafc6bc5
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Module\Admin;
|
namespace Zotlabs\Module\Admin;
|
||||||
|
|
||||||
|
use App;
|
||||||
use \Zotlabs\Storage\GitRepo;
|
use \Zotlabs\Storage\GitRepo;
|
||||||
use \Michelf\MarkdownExtra;
|
use \Michelf\MarkdownExtra;
|
||||||
|
|
||||||
@ -253,14 +254,14 @@ class Addons {
|
|||||||
* Single plugin
|
* Single plugin
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (\App::$argc == 3){
|
if (App::$argc == 3){
|
||||||
$plugin = \App::$argv[2];
|
$plugin = App::$argv[2];
|
||||||
if (!is_file("addon/$plugin/$plugin.php")){
|
if (!is_file("addon/$plugin/$plugin.php")){
|
||||||
notice( t("Item not found.") );
|
notice( t("Item not found.") );
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$enabled = in_array($plugin,\App::$plugins);
|
$enabled = in_array($plugin,App::$plugins);
|
||||||
$info = get_plugin_info($plugin);
|
$info = get_plugin_info($plugin);
|
||||||
$x = check_plugin_versions($info);
|
$x = check_plugin_versions($info);
|
||||||
|
|
||||||
@ -268,11 +269,11 @@ class Addons {
|
|||||||
|
|
||||||
if($enabled && ! $x) {
|
if($enabled && ! $x) {
|
||||||
$enabled = false;
|
$enabled = false;
|
||||||
$idz = array_search($plugin, \App::$plugins);
|
$idz = array_search($plugin, App::$plugins);
|
||||||
if ($idz !== false) {
|
if ($idz !== false) {
|
||||||
unset(\App::$plugins[$idz]);
|
unset(App::$plugins[$idz]);
|
||||||
uninstall_plugin($plugin);
|
uninstall_plugin($plugin);
|
||||||
set_config("system","addon", implode(", ",\App::$plugins));
|
set_config("system","addon", implode(", ",App::$plugins));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$info['disabled'] = 1-intval($x);
|
$info['disabled'] = 1-intval($x);
|
||||||
@ -281,19 +282,19 @@ class Addons {
|
|||||||
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
|
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
|
||||||
$pinstalled = false;
|
$pinstalled = false;
|
||||||
// Toggle plugin status
|
// Toggle plugin status
|
||||||
$idx = array_search($plugin, \App::$plugins);
|
$idx = array_search($plugin, App::$plugins);
|
||||||
if ($idx !== false){
|
if ($idx !== false){
|
||||||
unset(\App::$plugins[$idx]);
|
unset(App::$plugins[$idx]);
|
||||||
uninstall_plugin($plugin);
|
uninstall_plugin($plugin);
|
||||||
$pinstalled = false;
|
$pinstalled = false;
|
||||||
info( sprintf( t("Plugin %s disabled."), $plugin ) );
|
info( sprintf( t("Plugin %s disabled."), $plugin ) );
|
||||||
} else {
|
} else {
|
||||||
\App::$plugins[] = $plugin;
|
App::$plugins[] = $plugin;
|
||||||
install_plugin($plugin);
|
install_plugin($plugin);
|
||||||
$pinstalled = true;
|
$pinstalled = true;
|
||||||
info( sprintf( t("Plugin %s enabled."), $plugin ) );
|
info( sprintf( t("Plugin %s enabled."), $plugin ) );
|
||||||
}
|
}
|
||||||
set_config("system","addon", implode(", ",\App::$plugins));
|
set_config("system","addon", implode(", ",App::$plugins));
|
||||||
|
|
||||||
if($pinstalled) {
|
if($pinstalled) {
|
||||||
@require_once("addon/$plugin/$plugin.php");
|
@require_once("addon/$plugin/$plugin.php");
|
||||||
@ -305,7 +306,7 @@ class Addons {
|
|||||||
|
|
||||||
// display plugin details
|
// display plugin details
|
||||||
|
|
||||||
if (in_array($plugin, \App::$plugins)){
|
if (in_array($plugin, App::$plugins)){
|
||||||
$status = 'on';
|
$status = 'on';
|
||||||
$action = t('Disable');
|
$action = t('Disable');
|
||||||
} else {
|
} else {
|
||||||
@ -380,18 +381,18 @@ class Addons {
|
|||||||
|
|
||||||
list($tmp, $id) = array_map('trim', explode('/', $file));
|
list($tmp, $id) = array_map('trim', explode('/', $file));
|
||||||
$info = get_plugin_info($id);
|
$info = get_plugin_info($id);
|
||||||
$enabled = in_array($id,\App::$plugins);
|
$enabled = in_array($id,App::$plugins);
|
||||||
$x = check_plugin_versions($info);
|
$x = check_plugin_versions($info);
|
||||||
|
|
||||||
// disable plugins which are installed but incompatible versions
|
// disable plugins which are installed but incompatible versions
|
||||||
|
|
||||||
if($enabled && ! $x) {
|
if($enabled && ! $x) {
|
||||||
$enabled = false;
|
$enabled = false;
|
||||||
$idz = array_search($id, \App::$plugins);
|
$idz = array_search($id, App::$plugins);
|
||||||
if ($idz !== false) {
|
if ($idz !== false) {
|
||||||
unset(\App::$plugins[$idz]);
|
unset(App::$plugins[$idz]);
|
||||||
uninstall_plugin($id);
|
uninstall_plugin($id);
|
||||||
set_config("system","addon", implode(", ",\App::$plugins));
|
set_config("system","addon", implode(", ",App::$plugins));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$info['disabled'] = 1-intval($x);
|
$info['disabled'] = 1-intval($x);
|
||||||
|
@ -35,13 +35,6 @@ class Cloud extends \Zotlabs\Web\Controller {
|
|||||||
if (argc() > 1)
|
if (argc() > 1)
|
||||||
$which = argv(1);
|
$which = argv(1);
|
||||||
|
|
||||||
|
|
||||||
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
|
|
||||||
notice( t('Permission denied.') . EOL);
|
|
||||||
construct_page();
|
|
||||||
killme();
|
|
||||||
}
|
|
||||||
|
|
||||||
$profile = 0;
|
$profile = 0;
|
||||||
|
|
||||||
if ($which)
|
if ($which)
|
||||||
|
@ -95,6 +95,8 @@ class Dav extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
|
|
||||||
$auth = new \Zotlabs\Storage\BasicAuth();
|
$auth = new \Zotlabs\Storage\BasicAuth();
|
||||||
|
$auth->observer = get_observer_hash();
|
||||||
|
|
||||||
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
|
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
|
||||||
|
|
||||||
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
|
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
|
||||||
|
@ -720,7 +720,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
|||||||
* @return array Directory[]
|
* @return array Directory[]
|
||||||
*/
|
*/
|
||||||
function ChannelList(&$auth) {
|
function ChannelList(&$auth) {
|
||||||
$ret = array();
|
$ret = [];
|
||||||
|
|
||||||
|
if (intval(get_config('system','cloud_disable_siteroot'))) {
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
|
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
|
||||||
intval(PAGE_HIDDEN)
|
intval(PAGE_HIDDEN)
|
||||||
@ -730,8 +734,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
|||||||
foreach ($r as $rr) {
|
foreach ($r as $rr) {
|
||||||
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
|
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
|
||||||
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
|
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
|
||||||
// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
|
$ret[] = new Directory($rr['channel_address'], $auth);
|
||||||
$ret[] = new Directory('/cloud/' . $rr['channel_address'], $auth);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,13 @@ Extract somewere and launch zotsh.py
|
|||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
Update: 2019-08-14
|
||||||
|
|
||||||
|
Have just looked at this after several years of bitrot and made some updates.
|
||||||
|
it functions for cli DAV access on your assigned hub, but magic-auth to dav repos on other hubs
|
||||||
|
(e.g. the host command) needs to be updated to work with openwebauth.
|
||||||
|
|
||||||
|
----
|
||||||
ZotSH is a command line WebDAV client for Hubzilla.
|
ZotSH is a command line WebDAV client for Hubzilla.
|
||||||
It knows how to magic-auth to remote hubs using Zot.
|
It knows how to magic-auth to remote hubs using Zot.
|
||||||
|
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -1,202 +1,202 @@
|
|||||||
import requests
|
import requests
|
||||||
import platform
|
import platform
|
||||||
from numbers import Number
|
from numbers import Number
|
||||||
import xml.etree.cElementTree as xml
|
import xml.etree.cElementTree as xml
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
py_majversion, py_minversion, py_revversion = platform.python_version_tuple()
|
py_majversion, py_minversion, py_revversion = platform.python_version_tuple()
|
||||||
|
|
||||||
if py_majversion == '2':
|
if py_majversion == '2':
|
||||||
from httplib import responses as HTTP_CODES
|
from httplib import responses as HTTP_CODES
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
else:
|
else:
|
||||||
from http.client import responses as HTTP_CODES
|
from http.client import responses as HTTP_CODES
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
DOWNLOAD_CHUNK_SIZE_BYTES = 1 * 1024 * 1024
|
DOWNLOAD_CHUNK_SIZE_BYTES = 1 * 1024 * 1024
|
||||||
|
|
||||||
class WebdavException(Exception):
|
class WebdavException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ConnectionFailed(WebdavException):
|
class ConnectionFailed(WebdavException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def codestr(code):
|
def codestr(code):
|
||||||
return HTTP_CODES.get(code, 'UNKNOWN')
|
return HTTP_CODES.get(code, 'UNKNOWN')
|
||||||
|
|
||||||
|
|
||||||
File = namedtuple('File', ['name', 'size', 'mtime', 'ctime', 'contenttype'])
|
File = namedtuple('File', ['name', 'size', 'mtime', 'ctime', 'contenttype'])
|
||||||
|
|
||||||
|
|
||||||
def prop(elem, name, default=None):
|
def prop(elem, name, default=None):
|
||||||
child = elem.find('.//{DAV:}' + name)
|
child = elem.find('.//{DAV:}' + name)
|
||||||
return default if child is None else child.text
|
return default if child is None or child.text is None else child.text
|
||||||
|
|
||||||
|
|
||||||
def elem2file(elem):
|
def elem2file(elem):
|
||||||
return File(
|
return File(
|
||||||
prop(elem, 'href'),
|
prop(elem, 'href'),
|
||||||
int(prop(elem, 'getcontentlength', 0)),
|
int(prop(elem, 'getcontentlength', 0)),
|
||||||
prop(elem, 'getlastmodified', ''),
|
prop(elem, 'getlastmodified', ''),
|
||||||
prop(elem, 'creationdate', ''),
|
prop(elem, 'creationdate', ''),
|
||||||
prop(elem, 'getcontenttype', ''),
|
prop(elem, 'getcontenttype', ''),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OperationFailed(WebdavException):
|
class OperationFailed(WebdavException):
|
||||||
_OPERATIONS = dict(
|
_OPERATIONS = dict(
|
||||||
HEAD = "get header",
|
HEAD = "get header",
|
||||||
GET = "download",
|
GET = "download",
|
||||||
PUT = "upload",
|
PUT = "upload",
|
||||||
DELETE = "delete",
|
DELETE = "delete",
|
||||||
MKCOL = "create directory",
|
MKCOL = "create directory",
|
||||||
PROPFIND = "list directory",
|
PROPFIND = "list directory",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, method, path, expected_code, actual_code):
|
def __init__(self, method, path, expected_code, actual_code):
|
||||||
self.method = method
|
self.method = method
|
||||||
self.path = path
|
self.path = path
|
||||||
self.expected_code = expected_code
|
self.expected_code = expected_code
|
||||||
self.actual_code = actual_code
|
self.actual_code = actual_code
|
||||||
operation_name = self._OPERATIONS[method]
|
operation_name = self._OPERATIONS[method]
|
||||||
self.reason = 'Failed to {operation_name} "{path}"'.format(**locals())
|
self.reason = 'Failed to {operation_name} "{path}"'.format(**locals())
|
||||||
expected_codes = (expected_code,) if isinstance(expected_code, Number) else expected_code
|
expected_codes = (expected_code,) if isinstance(expected_code, Number) else expected_code
|
||||||
expected_codes_str = ", ".join('{0} {1}'.format(code, codestr(code)) for code in expected_codes)
|
expected_codes_str = ", ".join('{0} {1}'.format(code, codestr(code)) for code in expected_codes)
|
||||||
actual_code_str = codestr(actual_code)
|
actual_code_str = codestr(actual_code)
|
||||||
msg = '''\
|
msg = '''\
|
||||||
{self.reason}.
|
{self.reason}.
|
||||||
Operation : {method} {path}
|
Operation : {method} {path}
|
||||||
Expected code : {expected_codes_str}
|
Expected code : {expected_codes_str}
|
||||||
Actual code : {actual_code} {actual_code_str}'''.format(**locals())
|
Actual code : {actual_code} {actual_code_str}'''.format(**locals())
|
||||||
super(OperationFailed, self).__init__(msg)
|
super(OperationFailed, self).__init__(msg)
|
||||||
|
|
||||||
class Client(object):
|
class Client(object):
|
||||||
def __init__(self, host, port=0, auth=None, username=None, password=None,
|
def __init__(self, host, port=0, auth=None, username=None, password=None,
|
||||||
protocol='http', verify_ssl=True, path=None, cert=None, session=None):
|
protocol='http', verify_ssl=True, path=None, cert=None, session=None):
|
||||||
if not port:
|
if not port:
|
||||||
port = 443 if protocol == 'https' else 80
|
port = 443 if protocol == 'https' else 80
|
||||||
self.baseurl = '{0}://{1}:{2}'.format(protocol, host, port)
|
self.baseurl = '{0}://{1}:{2}'.format(protocol, host, port)
|
||||||
if path:
|
if path:
|
||||||
self.baseurl = '{0}/{1}'.format(self.baseurl, path)
|
self.baseurl = '{0}/{1}'.format(self.baseurl, path)
|
||||||
self.cwd = '/'
|
self.cwd = '/'
|
||||||
if session is None:
|
if session is None:
|
||||||
self.session = requests.session()
|
self.session = requests.session()
|
||||||
else:
|
else:
|
||||||
self.session = session
|
self.session = session
|
||||||
self.session.verify = verify_ssl
|
self.session.verify = verify_ssl
|
||||||
self.session.stream = True
|
self.session.stream = True
|
||||||
|
|
||||||
if cert:
|
if cert:
|
||||||
self.session.cert = cert
|
self.session.cert = cert
|
||||||
|
|
||||||
if auth:
|
if auth:
|
||||||
self.session.auth = auth
|
self.session.auth = auth
|
||||||
elif username and password:
|
elif username and password:
|
||||||
self.session.auth = (username, password)
|
self.session.auth = (username, password)
|
||||||
|
|
||||||
def _send(self, method, path, expected_code, **kwargs):
|
def _send(self, method, path, expected_code, **kwargs):
|
||||||
url = self._get_url(path).strip(".")
|
url = self._get_url(path).strip(".")
|
||||||
#~ print self.session
|
#~ print self.session
|
||||||
#~ print self.session.verify
|
#~ print self.session.verify
|
||||||
#~ print self.session.params
|
#~ print self.session.params
|
||||||
#~ print self.session.cookies
|
#~ print self.session.cookies
|
||||||
response = self.session.request(method, url, allow_redirects=False, **kwargs)
|
response = self.session.request(method, url, allow_redirects=False, **kwargs)
|
||||||
#~ print response.request.method
|
#~ print response.request.method
|
||||||
#~ print response.request.url
|
#~ print response.request.url
|
||||||
if isinstance(expected_code, Number) and response.status_code != expected_code \
|
if isinstance(expected_code, Number) and response.status_code != expected_code \
|
||||||
or not isinstance(expected_code, Number) and response.status_code not in expected_code:
|
or not isinstance(expected_code, Number) and response.status_code not in expected_code:
|
||||||
raise OperationFailed(method, path, expected_code, response.status_code)
|
raise OperationFailed(method, path, expected_code, response.status_code)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def _get_url(self, path):
|
def _get_url(self, path):
|
||||||
path = str(path).strip()
|
path = str(path).strip()
|
||||||
if path.startswith('/'):
|
if path.startswith('/'):
|
||||||
return self.baseurl + path
|
return self.baseurl + path
|
||||||
return "".join((self.baseurl, self.cwd, path))
|
return "".join((self.baseurl, self.cwd, path))
|
||||||
|
|
||||||
def cd(self, path):
|
def cd(self, path):
|
||||||
path = path.strip()
|
path = path.strip()
|
||||||
if not path:
|
if not path:
|
||||||
return
|
return
|
||||||
stripped_path = '/'.join(part for part in path.split('/') if part) + '/'
|
stripped_path = '/'.join(part for part in path.split('/') if part) + '/'
|
||||||
|
|
||||||
if stripped_path == '/':
|
if stripped_path == '/':
|
||||||
self.cwd = stripped_path
|
self.cwd = stripped_path
|
||||||
elif path.startswith('/'):
|
elif path.startswith('/'):
|
||||||
self.cwd = '/' + stripped_path
|
self.cwd = '/' + stripped_path
|
||||||
elif stripped_path == "./":
|
elif stripped_path == "./":
|
||||||
return
|
return
|
||||||
elif stripped_path == "../":
|
elif stripped_path == "../":
|
||||||
self.cwd ='/'.join( self.cwd.split('/')[:-2] ) + '/'
|
self.cwd ='/'.join( self.cwd.split('/')[:-2] ) + '/'
|
||||||
else:
|
else:
|
||||||
self.cwd += stripped_path
|
self.cwd += stripped_path
|
||||||
|
|
||||||
def mkdir(self, path, safe=False):
|
def mkdir(self, path, safe=False):
|
||||||
expected_codes = 201 if not safe else (201, 301, 405)
|
expected_codes = 201 if not safe else (201, 301, 405)
|
||||||
self._send('MKCOL', path, expected_codes)
|
self._send('MKCOL', path, expected_codes)
|
||||||
|
|
||||||
def mkdirs(self, path):
|
def mkdirs(self, path):
|
||||||
dirs = [d for d in path.split('/') if d]
|
dirs = [d for d in path.split('/') if d]
|
||||||
if not dirs:
|
if not dirs:
|
||||||
return
|
return
|
||||||
if path.startswith('/'):
|
if path.startswith('/'):
|
||||||
dirs[0] = '/' + dirs[0]
|
dirs[0] = '/' + dirs[0]
|
||||||
old_cwd = self.cwd
|
old_cwd = self.cwd
|
||||||
try:
|
try:
|
||||||
for dir in dirs:
|
for dir in dirs:
|
||||||
try:
|
try:
|
||||||
self.mkdir(dir, safe=True)
|
self.mkdir(dir, safe=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if e.actual_code == 409:
|
if e.actual_code == 409:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
self.cd(dir)
|
self.cd(dir)
|
||||||
finally:
|
finally:
|
||||||
self.cd(old_cwd)
|
self.cd(old_cwd)
|
||||||
|
|
||||||
def rmdir(self, path, safe=False):
|
def rmdir(self, path, safe=False):
|
||||||
path = str(path).rstrip('/') + '/'
|
path = str(path).rstrip('/') + '/'
|
||||||
expected_codes = 204 if not safe else (204, 404)
|
expected_codes = 204 if not safe else (204, 404)
|
||||||
self._send('DELETE', path, expected_codes)
|
self._send('DELETE', path, expected_codes)
|
||||||
|
|
||||||
def delete(self, path):
|
def delete(self, path):
|
||||||
self._send('DELETE', path, 204)
|
self._send('DELETE', path, 204)
|
||||||
|
|
||||||
def upload(self, local_path_or_fileobj, remote_path):
|
def upload(self, local_path_or_fileobj, remote_path):
|
||||||
if isinstance(local_path_or_fileobj, basestring):
|
if isinstance(local_path_or_fileobj, basestring):
|
||||||
with open(local_path_or_fileobj, 'rb') as f:
|
with open(local_path_or_fileobj, 'rb') as f:
|
||||||
self._upload(f, remote_path)
|
self._upload(f, remote_path)
|
||||||
else:
|
else:
|
||||||
self._upload(local_path_or_fileobj, remote_path)
|
self._upload(local_path_or_fileobj, remote_path)
|
||||||
|
|
||||||
def _upload(self, fileobj, remote_path):
|
def _upload(self, fileobj, remote_path):
|
||||||
self._send('PUT', remote_path, (200, 201, 204), data=fileobj)
|
self._send('PUT', remote_path, (200, 201, 204), data=fileobj)
|
||||||
|
|
||||||
def download(self, remote_path, local_path_or_fileobj):
|
def download(self, remote_path, local_path_or_fileobj):
|
||||||
response = self._send('GET', remote_path, 200, stream=True)
|
response = self._send('GET', remote_path, 200, stream=True)
|
||||||
if isinstance(local_path_or_fileobj, basestring):
|
if isinstance(local_path_or_fileobj, basestring):
|
||||||
with open(local_path_or_fileobj, 'wb') as f:
|
with open(local_path_or_fileobj, 'wb') as f:
|
||||||
self._download(f, response)
|
self._download(f, response)
|
||||||
else:
|
else:
|
||||||
self._download(local_path_or_fileobj, response)
|
self._download(local_path_or_fileobj, response)
|
||||||
|
|
||||||
def _download(self, fileobj, response):
|
def _download(self, fileobj, response):
|
||||||
for chunk in response.iter_content(DOWNLOAD_CHUNK_SIZE_BYTES):
|
for chunk in response.iter_content(DOWNLOAD_CHUNK_SIZE_BYTES):
|
||||||
fileobj.write(chunk)
|
fileobj.write(chunk)
|
||||||
|
|
||||||
def ls(self, remote_path='.'):
|
def ls(self, remote_path='.'):
|
||||||
headers = {'Depth': '1'}
|
headers = {'Depth': '1'}
|
||||||
response = self._send('PROPFIND', remote_path, (207, 301), headers=headers)
|
response = self._send('PROPFIND', remote_path, (207, 301), headers=headers)
|
||||||
|
|
||||||
# Redirect
|
# Redirect
|
||||||
if response.status_code == 301:
|
if response.status_code == 301:
|
||||||
url = urlparse(response.headers['location'])
|
url = urlparse(response.headers['location'])
|
||||||
return self.ls(url.path)
|
return self.ls(url.path)
|
||||||
|
|
||||||
tree = xml.fromstring(response.content)
|
tree = xml.fromstring(response.content)
|
||||||
return [elem2file(elem) for elem in tree.findall('{DAV:}response')]
|
return [elem2file(elem) for elem in tree.findall('{DAV:}response')]
|
||||||
|
|
||||||
def exists(self, remote_path):
|
def exists(self, remote_path):
|
||||||
response = self._send('HEAD', remote_path, (200, 301, 404))
|
response = self._send('HEAD', remote_path, (200, 301, 404))
|
||||||
return True if response.status_code != 404 else False
|
return True if response.status_code != 404 else False
|
||||||
|
Binary file not shown.
@ -1,324 +1,313 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python
|
||||||
import sys, os
|
|
||||||
import ConfigParser
|
import sys, os
|
||||||
import requests
|
import ConfigParser
|
||||||
from requests.auth import HTTPBasicAuth
|
import requests
|
||||||
import easywebdav
|
from requests.auth import HTTPBasicAuth
|
||||||
import easywebdav.__version__ as easywebdavversion
|
import easywebdav
|
||||||
|
import easywebdav.__version__ as easywebdavversion
|
||||||
__version__= "0.0.2"
|
import base64
|
||||||
|
|
||||||
SERVER = None
|
__version__= "0.0.2"
|
||||||
USER = None
|
|
||||||
PASSWD = None
|
SERVER = None
|
||||||
VERIFY_SSL=True
|
USER = None
|
||||||
|
PASSWD = None
|
||||||
#####################################################
|
VERIFY_SSL=True
|
||||||
|
|
||||||
class CommandNotFound(Exception):
|
#####################################################
|
||||||
pass
|
|
||||||
|
class CommandNotFound(Exception):
|
||||||
class ZotSH(object):
|
pass
|
||||||
commands = ['cd','ls','exists','mkdir','mkdirs','rmdir','delete','upload','download',
|
|
||||||
'host', 'pwd','cat',
|
class ZotSH(object):
|
||||||
'lcd','lpwd', 'lls',
|
commands = ['cd','ls','exists','mkdir','mkdirs','rmdir','delete','upload','download',
|
||||||
'quit', 'help']
|
'host', 'pwd','cat',
|
||||||
def __init__(self, host, session=None, davclient=None):
|
'lcd','lpwd', 'lls',
|
||||||
self.sessions = {}
|
'quit', 'help']
|
||||||
self.host = host
|
def __init__(self, host, session=None, davclient=None):
|
||||||
self.session = session
|
self.sessions = {}
|
||||||
self.davclient = davclient
|
self.host = host
|
||||||
|
self.session = session
|
||||||
|
self.davclient = davclient
|
||||||
@property
|
|
||||||
def host(self):
|
|
||||||
return self._host
|
@property
|
||||||
|
def host(self):
|
||||||
@host.setter
|
return self._host
|
||||||
def host(self, host):
|
|
||||||
self._host = host
|
@host.setter
|
||||||
self._hostname = host.replace("https:","").replace("/","")
|
def host(self, host):
|
||||||
|
self._host = host
|
||||||
@property
|
self._hostname = host.replace("https:","").replace("/","")
|
||||||
def hostname(self):
|
|
||||||
return self._hostname
|
@property
|
||||||
|
def hostname(self):
|
||||||
@hostname.setter
|
return self._hostname
|
||||||
def hostname(self, hostname):
|
|
||||||
self._host = "https://%s/" % (hostname)
|
@hostname.setter
|
||||||
self._hostname = hostname
|
def hostname(self, hostname):
|
||||||
|
self._host = "https://%s/" % (hostname)
|
||||||
@property
|
self._hostname = hostname
|
||||||
def session(self):
|
|
||||||
return self._session
|
@property
|
||||||
|
def session(self):
|
||||||
@session.setter
|
return self._session
|
||||||
def session(self, session):
|
|
||||||
self._session = session
|
@session.setter
|
||||||
self.davclient = easywebdav.connect( self.hostname, protocol='https', session=session, path="cloud", verify_ssl=VERIFY_SSL)
|
def session(self, session):
|
||||||
|
self._session = session
|
||||||
@property
|
self.davclient = easywebdav.connect( self.hostname, protocol='https', session=session, path="dav", verify_ssl=VERIFY_SSL)
|
||||||
def PS1(self):
|
|
||||||
if self.davclient is None:
|
@property
|
||||||
return "[!]> "
|
def PS1(self):
|
||||||
return "%s:%s> " % (self.hostname, self.davclient.cwd)
|
if self.davclient is None:
|
||||||
|
return "[!]> "
|
||||||
def get_host_session(self, host=None):
|
return "%s:%s> " % (self.hostname, self.davclient.cwd)
|
||||||
#~ if host is None:
|
|
||||||
#~ host = self.host
|
def get_host_session(self, host=None):
|
||||||
#~ if not host.startswith("https"):
|
#~ if host is None:
|
||||||
#~ host = "https://%s/" % (host)
|
#~ host = self.host
|
||||||
#~ if host in self.sessions:
|
#~ if not host.startswith("https"):
|
||||||
#~ session = self.sessions[host]
|
#~ host = "https://%s/" % (host)
|
||||||
#~ else:
|
#~ if host in self.sessions:
|
||||||
#~ session = requests.Session()
|
#~ session = self.sessions[host]
|
||||||
#~ self.sessions[host] = session
|
#~ else:
|
||||||
#~ if not host == SERVER
|
#~ session = requests.Session()
|
||||||
#~ session.params.update({'davguest':1})
|
#~ self.sessions[host] = session
|
||||||
#~ return session
|
#~ if not host == SERVER
|
||||||
|
#~ session.params.update({'davguest':1})
|
||||||
if self.session is None:
|
#~ return session
|
||||||
session = requests.Session()
|
|
||||||
#session.params.update({'davguest':1})
|
if self.session is None:
|
||||||
else:
|
session = requests.Session()
|
||||||
session = self.session
|
#session.params.update({'davguest':1})
|
||||||
session.params.update({'davguest': (not host == SERVER) })
|
else:
|
||||||
return session
|
session = self.session
|
||||||
|
#session.params.update({'davguest': (not host == SERVER) })
|
||||||
def do(self, command, *args):
|
return session
|
||||||
if not command in self.commands:
|
|
||||||
raise CommandNotFound("Unknow command '%s'" % command)
|
def do(self, command, *args):
|
||||||
|
if not command in self.commands:
|
||||||
cmd = getattr(self, "cmd_%s"%command, None)
|
raise CommandNotFound("Unknown command '%s'" % command)
|
||||||
if cmd is None:
|
|
||||||
cmd = getattr(self.davclient, command)
|
cmd = getattr(self, "cmd_%s"%command, None)
|
||||||
|
if cmd is None:
|
||||||
return cmd(*args)
|
cmd = getattr(self.davclient, command)
|
||||||
|
|
||||||
def cmd_exists(self, *args):
|
return cmd(*args)
|
||||||
if (len(args)==0):
|
|
||||||
return
|
def cmd_exists(self, *args):
|
||||||
return self.davclient.exists(args[0])
|
if (len(args)==0):
|
||||||
|
return
|
||||||
def cmd_mkdir(self, *args):
|
return self.davclient.exists(args[0])
|
||||||
if (len(args)==0):
|
|
||||||
return
|
def cmd_mkdir(self, *args):
|
||||||
return self.davclient.mkdir(args[0])
|
if (len(args)==0):
|
||||||
|
return
|
||||||
def cmd_mkdirs(self, *args):
|
return self.davclient.mkdir(args[0])
|
||||||
if (len(args)==0):
|
|
||||||
return
|
def cmd_mkdirs(self, *args):
|
||||||
return self.davclient.mkdirs(args[0])
|
if (len(args)==0):
|
||||||
|
return
|
||||||
def cmd_rmdir(self, *args):
|
return self.davclient.mkdirs(args[0])
|
||||||
if (len(args)==0):
|
|
||||||
return
|
def cmd_rmdir(self, *args):
|
||||||
return self.davclient.rmdir(args[0])
|
if (len(args)==0):
|
||||||
|
return
|
||||||
def cmd_delete(self, *args):
|
return self.davclient.rmdir(args[0])
|
||||||
if (len(args)==0):
|
|
||||||
return
|
def cmd_delete(self, *args):
|
||||||
return self.davclient.delete(args[0])
|
if (len(args)==0):
|
||||||
|
return
|
||||||
def cmd_upload(self, *args):
|
return self.davclient.delete(args[0])
|
||||||
if (len(args)==0):
|
|
||||||
return
|
def cmd_upload(self, *args):
|
||||||
args = list(args)
|
if (len(args)==0):
|
||||||
if (len(args)==1):
|
return
|
||||||
args.append(args[0])
|
args = list(args)
|
||||||
|
if (len(args)==1):
|
||||||
return self.davclient.upload(args[0], args[1])
|
args.append(args[0])
|
||||||
|
|
||||||
def cmd_download(self, *args):
|
return self.davclient.upload(args[0], args[1])
|
||||||
if (len(args)==0):
|
|
||||||
return
|
def cmd_download(self, *args):
|
||||||
args = list(args)
|
if (len(args)==0):
|
||||||
if (len(args)==1):
|
return
|
||||||
args.append(args[0])
|
args = list(args)
|
||||||
|
if (len(args)==1):
|
||||||
return self.davclient.download(args[0], args[1])
|
args.append(args[0])
|
||||||
|
|
||||||
def cmd_host(self, *args):
|
return self.davclient.download(args[0], args[1])
|
||||||
if (len(args)==0):
|
|
||||||
return
|
def cmd_host(self, *args):
|
||||||
newhostname = args[0]
|
if (len(args)==0):
|
||||||
newhost = "https://%s/" % newhostname
|
return
|
||||||
if newhostname == "~" or newhost == SERVER:
|
newhostname = args[0]
|
||||||
# bach to home server
|
newhost = "https://%s/" % newhostname
|
||||||
self.host = SERVER
|
if newhostname == "~" or newhost == SERVER:
|
||||||
self.session = self.get_host_session(SERVER)
|
# bach to home server
|
||||||
return
|
self.host = SERVER
|
||||||
|
self.session = self.get_host_session(SERVER)
|
||||||
session_remote = self.get_host_session(newhost)
|
return
|
||||||
session_home = self.get_host_session(SERVER)
|
|
||||||
|
session_remote = self.get_host_session(newhost)
|
||||||
# call /magic on SERVER
|
session_home = self.get_host_session(SERVER)
|
||||||
r = session_home.get(
|
|
||||||
SERVER + "magic",
|
bnewhost = newhost + 'dav'
|
||||||
params={'dest': newhost},
|
bnewhost = bnewhost.encode('hex')
|
||||||
allow_redirects=False,
|
|
||||||
verify=VERIFY_SSL )
|
r = session_home.get(
|
||||||
|
SERVER + "magic",
|
||||||
if not 'location' in r.headers:
|
params={'bdest': bnewhost, 'owa': 1},
|
||||||
raise Exception("Cannot start magic auth to '%s'" % newhostname)
|
allow_redirects=True,
|
||||||
auth_url = r.headers['location']
|
verify=VERIFY_SSL )
|
||||||
|
|
||||||
|
self.hostname = newhostname
|
||||||
# call auth_url with "test" param
|
self.session = session_remote
|
||||||
|
|
||||||
r = session_remote.get(
|
|
||||||
auth_url,
|
def cmd_pwd(self, *args):
|
||||||
params={'test': 1 },
|
return "%s%s" % ( self.davclient.baseurl, self.davclient.cwd )
|
||||||
verify=VERIFY_SSL )
|
|
||||||
|
def cmd_ls(self, *args):
|
||||||
if r.json()['success']:
|
extra_args = ["-a", "-l", "-d"]
|
||||||
self.hostname = newhostname
|
|
||||||
self.session = session_remote
|
show_hidden = "-a" in args
|
||||||
else:
|
show_list = "-l" in args
|
||||||
raise Exception("Cannot magic auth to '%s'" % newhostname)
|
show_only_dir = "-d" in args
|
||||||
|
args = [ a for a in args if not a in extra_args ]
|
||||||
|
|
||||||
def cmd_pwd(self, *args):
|
|
||||||
return "%s%s" % ( self.davclient.baseurl, self.davclient.cwd )
|
r = self.davclient.ls(*args)
|
||||||
|
l = max([ len(str(f.size)) for f in r ] + [7,])
|
||||||
def cmd_ls(self, *args):
|
|
||||||
extra_args = ["-a", "-l", "-d"]
|
def _fmt(type, size, name):
|
||||||
|
if show_list:
|
||||||
show_hidden = "-a" in args
|
return "%s %*d %s" % (type, l, f.size , name)
|
||||||
show_list = "-l" in args
|
else:
|
||||||
show_only_dir = "-d" in args
|
return name
|
||||||
args = [ a for a in args if not a in extra_args ]
|
|
||||||
|
if show_hidden :
|
||||||
|
print _fmt('d', 0, "./")
|
||||||
r = self.davclient.ls(*args)
|
if self.davclient.cwd!="/":
|
||||||
l = max([ len(str(f.size)) for f in r ] + [7,])
|
print _fmt('d', 0, "../")
|
||||||
|
|
||||||
def _fmt(type, size, name):
|
for f in r:
|
||||||
if show_list:
|
name = f.name.replace("/dav"+self.davclient.cwd,"")
|
||||||
return "%s %*d %s" % (type, l, f.size , name)
|
type = "-"
|
||||||
else:
|
if name.endswith("/"):
|
||||||
return name
|
type = "d"
|
||||||
|
if name!="":
|
||||||
if show_hidden :
|
if show_hidden or not name.startswith("."):
|
||||||
print _fmt('d', 0, "./")
|
if not show_only_dir or type=="d":
|
||||||
if self.davclient.cwd!="/":
|
print _fmt(type, f.size , name)
|
||||||
print _fmt('d', 0, "../")
|
|
||||||
|
def cmd_lpwd(self, *args):
|
||||||
for f in r:
|
return os.getcwd()
|
||||||
name = f.name.replace("/cloud"+self.davclient.cwd,"")
|
|
||||||
type = "-"
|
def cmd_lcd(self, *args):
|
||||||
if name.endswith("/"):
|
if (len(args)==0):
|
||||||
type = "d"
|
return
|
||||||
if name!="":
|
os.chdir(args[0])
|
||||||
if show_hidden or not name.startswith("."):
|
|
||||||
if not show_only_dir or type=="d":
|
def cmd_lls(self, *args):
|
||||||
print _fmt(type, f.size , name)
|
for f in os.listdir(os.getcwd()):
|
||||||
|
if os.path.isdir(f):
|
||||||
def cmd_lpwd(self, *args):
|
f=f+"/"
|
||||||
return os.getcwd()
|
print f
|
||||||
|
|
||||||
def cmd_lcd(self, *args):
|
def cmd_help(self, *args):
|
||||||
if (len(args)==0):
|
print "ZotSH",__version__
|
||||||
return
|
print
|
||||||
os.chdir(args[0])
|
print "Commands:"
|
||||||
|
for c in self.commands:
|
||||||
def cmd_lls(self, *args):
|
print "\t",c
|
||||||
for f in os.listdir(os.getcwd()):
|
print
|
||||||
if os.path.isdir(f):
|
print "easywebdav", easywebdavversion.__version__, "(mod)"
|
||||||
f=f+"/"
|
print "requests", requests.__version__
|
||||||
print f
|
|
||||||
|
def cmd_cat(self,*args):
|
||||||
def cmd_help(self, *args):
|
if (len(args)==0):
|
||||||
print "ZotSH",__version__
|
return
|
||||||
print
|
rfile = args[0]
|
||||||
print "Commands:"
|
resp = self.davclient._send('GET', rfile, (200,))
|
||||||
for c in self.commands:
|
print resp.text
|
||||||
print "\t",c
|
|
||||||
print
|
def load_conf():
|
||||||
print "easywebdav", easywebdavversion.__version__, "(mod)"
|
global SERVER,USER,PASSWD,VERIFY_SSL
|
||||||
print "requests", requests.__version__
|
homedir = os.getenv("HOME")
|
||||||
|
if homedir is None:
|
||||||
def cmd_cat(self,*args):
|
homedir = os.path.join(os.getenv("HOMEDRIVE"), os.getenv("HOMEPATH"))
|
||||||
if (len(args)==0):
|
|
||||||
return
|
optsfile = ".zotshrc"
|
||||||
rfile = args[0]
|
if not os.path.isfile(optsfile):
|
||||||
resp = self.davclient._send('GET', rfile, (200,))
|
optsfile = os.path.join(homedir, ".zotshrc")
|
||||||
print resp.text
|
|
||||||
|
if not os.path.isfile(optsfile):
|
||||||
def load_conf():
|
print "Please create a configuration file called '.zotshrc':"
|
||||||
global SERVER,USER,PASSWD,VERIFY_SSL
|
print "[zotsh]"
|
||||||
homedir = os.getenv("HOME")
|
print "host = https://yourhost.com/"
|
||||||
if homedir is None:
|
print "username = your_username"
|
||||||
homedir = os.path.join(os.getenv("HOMEDRIVE"), os.getenv("HOMEPATH"))
|
print "password = your_password"
|
||||||
|
sys.exit(-1)
|
||||||
optsfile = ".zotshrc"
|
|
||||||
if not os.path.isfile(optsfile):
|
config = ConfigParser.ConfigParser()
|
||||||
optsfile = os.path.join(homedir, ".zotshrc")
|
config.read(optsfile)
|
||||||
|
SERVER = config.get('zotsh', 'host')
|
||||||
if not os.path.isfile(optsfile):
|
USER = config.get('zotsh', 'username')
|
||||||
print "Please create a configuration file called '.zotshrc':"
|
PASSWD = config.get('zotsh', 'password')
|
||||||
print "[zotsh]"
|
if config.has_option('zotsh', 'verify_ssl'):
|
||||||
print "host = https://yourhost.com/"
|
VERIFY_SSL = config.getboolean('zotsh', 'verify_ssl')
|
||||||
print "username = your_username"
|
|
||||||
print "password = your_password"
|
|
||||||
sys.exit(-1)
|
def zotsh():
|
||||||
|
|
||||||
config = ConfigParser.ConfigParser()
|
zotsh = ZotSH( SERVER)
|
||||||
config.read(optsfile)
|
|
||||||
SERVER = config.get('zotsh', 'host')
|
session_home = zotsh.get_host_session()
|
||||||
USER = config.get('zotsh', 'username')
|
|
||||||
PASSWD = config.get('zotsh', 'password')
|
#~ #login on home server
|
||||||
if config.has_option('zotsh', 'verify_ssl'):
|
print "loggin in..."
|
||||||
VERIFY_SSL = config.getboolean('zotsh', 'verify_ssl')
|
r = session_home.get(
|
||||||
|
SERVER + "api/account/verify_credentials",
|
||||||
|
auth=HTTPBasicAuth(USER, PASSWD),
|
||||||
def zotsh():
|
verify=VERIFY_SSL )
|
||||||
|
|
||||||
zotsh = ZotSH( SERVER)
|
print "Hi", r.json()['name']
|
||||||
|
|
||||||
session_home = zotsh.get_host_session()
|
zotsh.session = session_home
|
||||||
|
|
||||||
#~ #login on home server
|
# command loop
|
||||||
print "loggin in..."
|
input = raw_input(zotsh.PS1)
|
||||||
r = session_home.get(
|
while (input != "quit"):
|
||||||
SERVER + "api/account/verify_credentials",
|
input = input.strip()
|
||||||
auth=HTTPBasicAuth(USER, PASSWD),
|
if len(input)>0:
|
||||||
verify=VERIFY_SSL )
|
toks = [ x.strip() for x in input.split(" ") ]
|
||||||
|
|
||||||
print "Hi", r.json()['name']
|
command = toks[0]
|
||||||
|
args = toks[1:]
|
||||||
zotsh.session = session_home
|
try:
|
||||||
|
ret = zotsh.do(command, *args)
|
||||||
# command loop
|
except easywebdav.client.OperationFailed, e:
|
||||||
input = raw_input(zotsh.PS1)
|
print e
|
||||||
while (input != "quit"):
|
except CommandNotFound, e:
|
||||||
input = input.strip()
|
print e
|
||||||
if len(input)>0:
|
else:
|
||||||
toks = [ x.strip() for x in input.split(" ") ]
|
if ret is not None:
|
||||||
|
print ret
|
||||||
command = toks[0]
|
|
||||||
args = toks[1:]
|
|
||||||
try:
|
input = raw_input(zotsh.PS1)
|
||||||
ret = zotsh.do(command, *args)
|
|
||||||
except easywebdav.client.OperationFailed, e:
|
|
||||||
print e
|
|
||||||
except CommandNotFound, e:
|
|
||||||
print e
|
if __name__=="__main__":
|
||||||
else:
|
load_conf()
|
||||||
if ret is not None:
|
zotsh()
|
||||||
print ret
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
input = raw_input(zotsh.PS1)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__=="__main__":
|
|
||||||
load_conf()
|
|
||||||
zotsh()
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user