Browse Source

Final softchroot

* *settings.py* file is modified. Now - it saves chrotted settings correctly.
* Code blocks swapped (softchroot <-> browser )
* Method `is_root_abs` was added
* Tests added and improved
pull/5859/head
maxkoryukov 9 years ago
parent
commit
d932a2691f
  1. 69
      couchpotato/core/plugins/browser.py
  2. 33
      couchpotato/core/plugins/test_browser.py
  3. 8
      couchpotato/core/settings.py
  4. 9
      couchpotato/core/softchroot.py
  5. 10
      couchpotato/core/test_softchroot.py

69
couchpotato/core/plugins/browser.py

@ -10,7 +10,7 @@ from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import sp, ss, toUnicode from couchpotato.core.helpers.encoding import sp, ss, toUnicode
from couchpotato.core.helpers.variable import getUserDir from couchpotato.core.helpers.variable import getUserDir
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.core.softchroot import SoftChroot
log = CPLog(__name__) log = CPLog(__name__)
@ -33,13 +33,9 @@ autoload = 'FileBrowser'
class FileBrowser(Plugin): class FileBrowser(Plugin):
def __init__(self): def __init__(self):
self.soft_chroot_enabled = False # could be better way (#getsoftchroot)
soft_chroot_dir = Plugin.conf(self, 'soft_chroot', section='core')
self.soft_chroot = Plugin.conf(self, 'soft_chroot', section='core') self.soft_chroot = SoftChroot(soft_chroot_dir)
if None != self.soft_chroot:
self.soft_chroot = self.soft_chroot.strip()
self.soft_chroot = self.soft_chroot.rstrip(os.path.sep) + os.path.sep
self.soft_chroot_enabled = True
addApiView('directory.list', self.view, docs = { addApiView('directory.list', self.view, docs = {
'desc': 'Return the directory list of a given directory', 'desc': 'Return the directory list of a given directory',
@ -85,51 +81,18 @@ class FileBrowser(Plugin):
return driveletters return driveletters
def soft_chroot_is_subdir(self, path):
if None == path:
return False
if not path.endswith(os.path.sep):
path += os.path.sep
return path.startswith(self.soft_chroot)
def soft_chroot_add(self, path):
if None == path or len(path)==0:
return self.soft_chroot
if not path.startswith(os.path.sep):
raise ValueError("path must starts with '/'")
return self.soft_chroot[:-1] + path
def soft_chroot_cut(self, path):
if None == path or 0==len(path):
raise ValueError('path is empty')
if path == self.soft_chroot.rstrip(os.path.sep):
return '/'
if not path.startswith(self.soft_chroot):
raise ValueError("path must starts with soft_chroot")
l = len(self.soft_chroot)-1
return path[l:]
def view(self, path = '/', show_hidden = True, **kwargs): def view(self, path = '/', show_hidden = True, **kwargs):
home = getUserDir() home = getUserDir()
if self.soft_chroot_enabled: if self.soft_chroot.enabled:
if not self.soft_chroot_is_subdir(home): if not self.soft_chroot.is_subdir(home):
home = self.soft_chroot home = self.soft_chroot.chdir
if not path: if not path:
path = home path = home
if path.endswith(os.path.sep): if path.endswith(os.path.sep):
path = path.rstrip(os.path.sep) path = path.rstrip(os.path.sep)
elif self.soft_chroot_enabled: elif self.soft_chroot.enabled:
path = self.soft_chroot_add(path) path = self.soft_chroot.add(path)
try: try:
dirs = self.getDirectories(path = path, show_hidden = show_hidden) dirs = self.getDirectories(path = path, show_hidden = show_hidden)
@ -137,8 +100,8 @@ class FileBrowser(Plugin):
log.error('Failed getting directory "%s" : %s', (path, traceback.format_exc())) log.error('Failed getting directory "%s" : %s', (path, traceback.format_exc()))
dirs = [] dirs = []
if self.soft_chroot_enabled: if self.soft_chroot.enabled:
dirs = map(self.soft_chroot_cut, dirs) dirs = map(self.soft_chroot.cut, dirs)
parent = os.path.dirname(path.rstrip(os.path.sep)) parent = os.path.dirname(path.rstrip(os.path.sep))
if parent == path.rstrip(os.path.sep): if parent == path.rstrip(os.path.sep):
@ -149,18 +112,18 @@ class FileBrowser(Plugin):
# TODO : check on windows: # TODO : check on windows:
is_root = path == '/' is_root = path == '/'
if self.soft_chroot_enabled: if self.soft_chroot.enabled:
# path could contain '/' on end, and could not contain.. # path could contain '/' on end, and could not contain..
# but in 'soft-chrooted' environment path could be included in chroot_dir only when it is root # but in 'soft-chrooted' environment path could be included in chroot_dir only when it is root
is_root = self.soft_chroot.startswith(path) is_root = self.soft_chroot.is_root_abs(path)
# fix paths: # fix paths:
if self.soft_chroot_is_subdir(parent): if self.soft_chroot.is_subdir(parent):
parent = self.soft_chroot_cut(parent) parent = self.soft_chroot.cut(parent)
else: else:
parent = os.path.sep parent = os.path.sep
home = self.soft_chroot_cut(home) home = self.soft_chroot.cut(home)
return { return {
'is_root': is_root, 'is_root': is_root,

33
couchpotato/core/plugins/test_browser.py

@ -6,6 +6,7 @@ from unittest import TestCase
#from mock import MagicMock #from mock import MagicMock
from couchpotato.core.plugins.browser import FileBrowser from couchpotato.core.plugins.browser import FileBrowser
from couchpotato.core.softchroot import SoftChroot
CHROOT_DIR = '/tmp/' CHROOT_DIR = '/tmp/'
@ -14,8 +15,7 @@ class FileBrowserChrootedTest(TestCase):
self.b = FileBrowser() self.b = FileBrowser()
# TODO : remove scrutch: # TODO : remove scrutch:
self.b.soft_chroot = CHROOT_DIR self.b.soft_chroot = SoftChroot(CHROOT_DIR)
self.b.soft_chroot_enabled = True
# Logger # Logger
logger = logging.getLogger() logger = logging.getLogger()
@ -27,34 +27,7 @@ class FileBrowserChrootedTest(TestCase):
#logger.addHandler(hdlr) #logger.addHandler(hdlr)
def test_soft_chroot_enabled(self): def test_soft_chroot_enabled(self):
self.assertTrue( self.b.soft_chroot_enabled) self.assertTrue( self.b.soft_chroot.enabled)
def test_soft_chroot_is_subdir(self):
self.assertFalse( self.b.soft_chroot_is_subdir('') )
self.assertFalse( self.b.soft_chroot_is_subdir(None) )
self.assertTrue( self.b.soft_chroot_is_subdir(CHROOT_DIR) )
noslash = CHROOT_DIR[:-1]
self.assertTrue( self.b.soft_chroot_is_subdir(noslash) )
self.assertTrue( self.b.soft_chroot_is_subdir(CHROOT_DIR + 'come') )
def test_soft_chroot_add(self):
with self.assertRaises(ValueError):
self.b.soft_chroot_add('no_leading_slash')
self.assertEqual( self.b.soft_chroot_add(None), CHROOT_DIR )
self.assertEqual( self.b.soft_chroot_add(''), CHROOT_DIR )
self.assertEqual( self.b.soft_chroot_add('/asdf'), CHROOT_DIR + 'asdf' )
def test_soft_chroot_cut(self):
with self.assertRaises(ValueError): self.b.soft_chroot_cut(None)
with self.assertRaises(ValueError): self.b.soft_chroot_cut('')
self.assertEqual( self.b.soft_chroot_cut(CHROOT_DIR + 'asdf'), '/asdf' )
self.assertEqual( self.b.soft_chroot_cut(CHROOT_DIR), '/' )
self.assertEqual( self.b.soft_chroot_cut(CHROOT_DIR.rstrip(os.path.sep)), '/' )
def test_view__chrooted_path_none(self): def test_view__chrooted_path_none(self):
#def view(self, path = '/', show_hidden = True, **kwargs): #def view(self, path = '/', show_hidden = True, **kwargs):

8
couchpotato/core/settings.py

@ -7,7 +7,7 @@ from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import mergeDicts, tryInt, tryFloat from couchpotato.core.helpers.variable import mergeDicts, tryInt, tryFloat
from couchpotato.core.softchroot import SoftChroot
class Settings(object): class Settings(object):
@ -210,6 +210,12 @@ class Settings(object):
option = kwargs.get('name') option = kwargs.get('name')
value = kwargs.get('value') value = kwargs.get('value')
if self.types[section][option] == 'directory':
# could be better way (#getsoftchroot)
soft_chroot_dir = self.get(option = 'soft_chroot', section = 'core', default = None )
soft_chroot = SoftChroot(soft_chroot_dir)
value = soft_chroot.add(str(value))
# See if a value handler is attached, use that as value # See if a value handler is attached, use that as value
new_value = fireEvent('setting.save.%s.%s' % (section, option), value, single = True) new_value = fireEvent('setting.save.%s.%s' % (section, option), value, single = True)

9
couchpotato/core/softchroot.py

@ -13,6 +13,15 @@ class SoftChroot:
self.chdir = self.chdir.rstrip(os.path.sep) + os.path.sep self.chdir = self.chdir.rstrip(os.path.sep) + os.path.sep
self.enabled = True self.enabled = True
def is_root_abs(self, abspath):
if not self.enabled:
raise Exception('chroot disabled')
if None == abspath:
return False
path = abspath.rstrip(os.path.sep) + os.path.sep
return self.chdir == path
def is_subdir(self, path): def is_subdir(self, path):
if not self.enabled: if not self.enabled:
return True return True

10
couchpotato/core/test_softchroot.py

@ -26,6 +26,16 @@ class SoftChrootEnabledTest(TestCase):
self.assertTrue( self.b.is_subdir(CHROOT_DIR + 'come') ) self.assertTrue( self.b.is_subdir(CHROOT_DIR + 'come') )
def test_is_root_abs(self):
self.assertFalse( self.b.is_root_abs('') )
self.assertFalse( self.b.is_root_abs(None) )
self.assertTrue( self.b.is_root_abs(CHROOT_DIR) )
noslash = CHROOT_DIR[:-1]
self.assertTrue( self.b.is_root_abs(noslash) )
self.assertFalse( self.b.is_root_abs(CHROOT_DIR + 'come') )
def test_add(self): def test_add(self):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
self.b.add('no_leading_slash') self.b.add('no_leading_slash')

Loading…
Cancel
Save