#!/usr/bin/env python2.4

import unittest
import sys
from CryptoBox import *
from CryptoBoxExceptions import *
import CryptoBoxSettings

class CryptoBoxPropsDeviceTests(unittest.TestCase):
	import CryptoBox
	cb = CryptoBox.CryptoBoxProps()
		
	def testAllowedDevices(self):
		'''isDeviceAllowed should accept permitted devices'''
		self.assertTrue(self.cb.isDeviceAllowed("/dev/loop"))
		self.assertTrue(self.cb.isDeviceAllowed("/dev/loop1"))
		self.assertTrue(self.cb.isDeviceAllowed("/dev/loop/urgd"))
		self.assertTrue(self.cb.isDeviceAllowed("/dev/usb/../loop1"))
	
	def testDeniedDevices(self):
		'''isDeviceAllowed should fail with not explicitly allowed devices'''
		self.assertFalse(self.cb.isDeviceAllowed("/dev/hda"))
		self.assertFalse(self.cb.isDeviceAllowed("/dev/loopa/../hda"))
		self.assertFalse(self.cb.isDeviceAllowed("/"))
	

class CryptoBoxPropsConfigTests(unittest.TestCase):
	'''test here if everything with the config turns right'''
	import os
	import CryptoBox
	
	files = {
		"configFileOK"	:  "cbox-test_ok.conf",
		"configFileBroken"	:  "cbox-test_broken.conf",
		"nameDBFile"	: "cryptobox_volumes.db",
		"pluginConf"	: "cryptobox_plugins.conf",
		"userDB"	: "cryptobox_users.db",
		"logFile"	: "cryptobox.log",
		"tmpdir"	: "cryptobox-mnt" }
	tmpdirname = ""
	filenames = {}
	configContentOK = """
[Main]
AllowedDevices  = /dev/loop
DefaultVolumePrefix = "Data "
DefaultCipher   = aes-cbc-essiv:sha256
[Locations]
SettingsDir    = %s
MountParentDir  = %s
TemplateDir		= ../templates
LangDir			= ../lang
DocDir			= ../doc/html
PluginDir		= ../plugins
EventDir			= ../event-scripts
[Log]
Level           = debug
Destination        = file
Details     = %s/cryptobox.log
[WebSettings]
Stylesheet	= /cryptobox-misc/cryptobox.css
[Programs]
blkid			= /sbin/blkid
cryptsetup		= /sbin/cryptsetup
super			= /usr/bin/super
CryptoBoxRootActions	= CryptoBoxRootActions
"""


	def setUp(self):
		'''generate all files in tmp and remember the names'''
		import tempfile
		os = self.os
		self.tmpdirname = tempfile.mkdtemp(prefix="cbox-")
		for file in self.files.keys():
			self.filenames[file] = os.path.join(self.tmpdirname, self.files[file])
		self.writeConfig()


	def tearDown(self):
		'''remove the created tmpfiles'''
		os = self.os
		# remove temp files
		for file in self.filenames.values():
			compl_name = os.path.join(self.tmpdirname, file)
			if os.path.exists(compl_name): 
				os.remove(compl_name)
		# remove temp dir
		os.rmdir(self.tmpdirname)


	def testConfigInit(self):
		'''Check various branches of config file loading'''
		import os
		self.assertRaises(CBConfigUnavailableError, self.CryptoBox.CryptoBoxProps,"/invalid/path/to/config/file")
		self.assertRaises(CBConfigUnavailableError, self.CryptoBox.CryptoBoxProps,"/etc/shadow")
		""" check one of the following things:
		1) are we successfully using an existing config file?
		2) do we break, if no config file is there?
		depending on the existence of a config file, only one of these conditions
		can be checked - hints for more comprehensive tests are appreciated :) """
		for a in CryptoBoxSettings.CryptoBoxSettings.CONF_LOCATIONS:
			if os.path.exists(a):
				self.CryptoBox.CryptoBoxProps()
				break	# this skips the 'else' clause
		else:	self.assertRaises(CBConfigUnavailableError, self.CryptoBox.CryptoBoxProps) 
		self.assertRaises(CBConfigUnavailableError, self.CryptoBox.CryptoBoxProps,[])

	
	def testBrokenConfigs(self):
		"""Check various broken configurations"""
		self.writeConfig("SettingsDir", "SettingsDir=/foo/bar", filename=self.filenames["configFileBroken"])
		self.assertRaises(CBConfigError, self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
		self.writeConfig("Level", "Level = ho", filename=self.filenames["configFileBroken"])
		self.assertRaises(CBConfigError, self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
		self.writeConfig("Details", "#out", filename=self.filenames["configFileBroken"])
		self.assertRaises(CBConfigError, self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
		self.writeConfig("super", "super=/bin/invalid/no", filename=self.filenames["configFileBroken"])
		self.assertRaises(CBConfigError, self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
		self.writeConfig("CryptoBoxRootActions", "#not here", filename=self.filenames["configFileBroken"])
		self.assertRaises(CBConfigError, self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
		self.writeConfig("CryptoBoxRootActions", "CryptoBoxRootActions = /bin/false", filename=self.filenames["configFileBroken"])
		self.assertRaises(CBEnvironmentError, self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
	

	def writeConfig(self, replace=None, newline=None, filename=None):
		"""write a config file and (optional) replace a line in it"""
		import re
		if not filename: filename = self.filenames["configFileOK"]
		content = self.configContentOK % (self.tmpdirname, self.tmpdirname, self.tmpdirname)
		if replace:
			pattern = re.compile('^' + replace + '\\s*=.*$', flags=re.M)
			content = re.sub(pattern, newline, content)
		cf = open(filename, "w")
		cf.write(content)
		cf.close()


if __name__ == "__main__":
	unittest.main()
