new plugins: 'format_fs', 'volume_mount', 'volume_props', 'shutdown' and 'volume_details'

new plugin attribute: "requestAuth"
This commit is contained in:
lars 2006-10-09 16:43:14 +00:00
parent 0e8a5daa73
commit ca13aebdc8
27 changed files with 920 additions and 45 deletions

View file

@ -3,6 +3,9 @@ import CryptoBoxPlugin
class date(CryptoBoxPlugin.CryptoBoxPlugin): class date(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "system" ]
requestAuth = False
def doAction(self, store=None, year=0, month=0, day=0, hour=0, minute=0): def doAction(self, store=None, year=0, month=0, day=0, hour=0, minute=0):
import datetime import datetime
if store: if store:

View file

@ -0,0 +1,93 @@
import CryptoBoxPlugin
class format_fs(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "volume" ]
requestAuth = True
## map filesystem types to the appropriate arguments for 'mkfs'
fsTypes = {
"windows": "vfat",
"linux": "ext3" }
containerTypes = [ "luks", "plain" ]
def doAction(self, store=None, fs_type="windows", container_type="luks", crypto_password=None, crypto_password2=None, confirm=None):
if not fs_type in self.fsTypes.keys():
self.cbox.info
return "format_volume"
self.hdf[self.hdf_prefix + "fs_type"] = fs_type
self.hdf[self.hdf_prefix + "container_type"] = container_type
for t in self.fsTypes.keys():
self.hdf[self.hdf_prefix + "fs_types." + t] = t
if store == "step1":
if not confirm:
self.cbox.log.warn("missing confirmation for formatting of filesystem: %s" % self.device)
self.hdf["Data.Warning"] = "Plugins.format_fs.FormatNotConfirmed"
return "volume_format"
if container_type == "luks":
return "volume_format_luks"
elif container_type == "plain":
return self.__format_plain(fs_type)
elif store == "step2":
if container_type == "luks":
return self.__format_luks(fs_type, crypto_password, crypto_password2)
else:
self.cbox.log.info("invalid input value for 'container_type': %s" % container_type)
return "volume_format"
elif store:
self.cbox.log.info("invalid input value for 'store': %s" % store)
return "volume_format"
else:
return "volume_format"
def getStatus(self):
return "no status"
def __format_plain(self, fsType):
try:
container = self.cbox.getContainer(self.device)
container.create(container.Types["plain"])
except CBVolumeIsActive:
self.hdf["Data.Warning"] = "VolumeMayNotBeMounted"
self.cbox.log.info("initialization is not possible as long as the device (%s) is mounted" % self.device)
return None
except CBContainerError, errMsg:
self.hdf["Data.Warning"] = "Plugins.format_fs.FormatFailed"
self.cbox.log.warn("initialization of device '%s' failed" % self.device)
self.cbox.log.warn("reason: %s" % errMsg)
return "volume_format"
else:
self.cbox.log.info("successfully initialized device '%s'" % self.device)
return None
def __format_luks(self, fsType, pw, pw2):
if not pw:
self.hdf["Data.Warning"] = "EmptyCryptoPassword"
self.cbox.log.warn("no crypto password was supplied for initialization of device '%s'" % self.device)
return "volume_format"
if pw != pw2:
self.hdf["Data.Warning"] = "DifferentCryptoPasswords"
self.cbox.log.warn("the crypto password was not repeated correctly for initialization of device '%s'" % self.device)
return "volume_format"
container = self.cbox.getContainer(self.device)
try:
container.create(container.Types["luks"], pw)
except CBVolumeIsActive:
self.hdf["Data.Warning"] = "VolumeMayNotBeMounted"
self.cbox.log.info("initialization is not possible as long as the device (%s) is mounted" % self.device)
return None
except CBContainerError, errMsg:
self.hdf["Data.Warning"] = "Plugins.format_fs.FormatFailed"
self.cbox.log.warn("initialization of device '%s' failed" % self.device)
self.cbox.log.warn("reason: %s" % errMsg)
return "volume_format"
else:
self.hdf["Data.Success"] = "Plugins.format_fs.FormatSuccess"
self.cbox.log.info("successfully initialized device '%s'" % self.device)
return None

View file

@ -0,0 +1,36 @@
Name = Create filesystems
Link = Format
Rank = 60
Title.Format = Initializing filesystem
Button.Format = Initialize filesystem
Text {
Confirm = Yes, I know what I am doing!
FormatWarning = All data of the selected filesystem will get lost!
FSType = Filesystem type
IsEncrypted = Encryption
Yes = Yes
No = No
UnmountBeforeInit = You must deactivate this volume before you may initialize it.
}
SuccessMessage {
FormatSuccess {
Title = Formatting successful
Text = The selected filesystem was successfully formatted.
}
}
WarningMessage {
FormatNotConfirmed {
Title = Confirmation missing
Text = You did not confirm this action by activating the checkbox.
}
FormatFailed {
Title = Formatting failed
Text = Formatting of the selected filesystem failed for unknown reasons - sorry!
}
}

View file

@ -0,0 +1,37 @@
<?cs # $Id$ ?>
<?cs include:Settings.TemplateDir + "/show_volume_header.cs" ?>
<h2><?cs var:html_escape(Lang.Plugins.format_fs.Title.Format) ?></h2>
<?cs if:Data.CurrentDisk.active ?>
<div class="unavailable_action">
<?cs var:html_escape(Lang.Plugins.format_fs.Text.UnmountBeforeInit) ?>
</div>
<?cs else ?>
<?cs call:print_form_header("plugins/format_fs") ?>
<p><label for="fs_type"><?cs var:html_escape(Lang.Plugins.format_fs.Text.FSType)
?>: </label><select name="fs_type" id="fs_type" size="0" ?>
<?cs each:x = Data.Plugins.format_fs.fs_types ?>
<option <?cs if:x == "windows" ?>selected="selected"<?cs /if ?>><?cs var:html_escape(x) ?></option><?cs /each ?>
</select></p>
<p><label for="container_type"><?cs var:html_escape(Lang.Plugins.format_fs.Text.IsEncrypted)
?>: <select name="container_type" id="container_type">
<option value="luks" <?cs if:Data.Plugins.format_fs.container_type != "plain" ?>selected="selected"<?cs /if ?>><?cs var:html_escape(Lang.Plugins.format_fs.Text.Yes) ?></option> -->
<option value="plain" <?cs if:Data.Plugins.format_fs.container_type == "plain" ?>selected="selected"<?cs /if ?>><?cs var:html_escape(Lang.Plugins.format_fs.Text.No) ?></option>
</select></p>
<p class="note"><?cs var:html_escape(Lang.Plugins.format_fs.Text.FormatWarning) ?></p>
<p><input type="checkbox" name="confirm" value="1" id="confirm"><label for="confirm"><?cs var:html_escape(Lang.Plugins.format_fs.Text.Confirm) ?><p/>
<input type="hidden" name="device" value="<?cs var:Data.CurrentDisk.device ?>" />
<input type="hidden" name="store" value="step1" />
<button type="submit"><?cs var:html_escape(Lang.Plugins.format_fs.Button.Format) ?></button>
</form>
<?cs /if ?>
<?cs include:Settings.TemplateDir + "/show_volume_footer.cs" ?>

View file

@ -0,0 +1,33 @@
<?cs # $Id$ ?>
<?cs include:Settings.TemplateDir + "/show_volume_header.cs" ?>
<h2><?cs var:html_escape(Lang.Plugins.format_fs.Title.Format) ?></h2>
<?cs if:Data.CurrentDisk.active ?>
<div class="unavailable_action">
<?cs var:html_escape(Lang.Plugins.format_fs.Text.UnmountBeforeInit) ?>
</div>
<?cs else ?>
<?cs call:print_form_header("plugins/format_fs") ?>
<p class="note"><?cs var:html_escape(Lang.Plugins.format_fs.Text.FormatWarning) ?></p>
<p><?cs var:html_escape(Lang.Plugins.format_fs.Text.FSType) ?>: <?cs var:html_escape(Data.Plugins.format_fs.fs_type) ?></p>
<p><?cs var:html_escape(Lang.Plugins.format_fs.Text.IsEncrypted) ?>: <?cs if:Data.Plugins.format_fs.container_type == "luks" ?><?cs
var:html_escape(Lang.Plugins.format_fs.Text.Yes) ?><?cs else ?><?cs
var:html_escape(Lang.Plugins.format_fs.Text.No) ?><?cs /if ?></p>
<p><label for="crypto_password"><?cs var:html_escape(Lang.Text.EnterNewCryptoPassword) ?></label> <input type="password" id="crypto_password" name="crypto_password" /></p>
<p><label for="crypto_password2"><?cs var:html_escape(Lang.Text.EnterSameCryptoPassword) ?></label> <input type="password" id="crypto_password2" name="crypto_password2" /></p>
<input type="hidden" name="device" value="<?cs var:Data.CurrentDisk.device ?>" />
<input type="hidden" name="fs_type" value="<?cs var:html_escape(Data.Plugins.format_fs.fs_type) ?>" />
<input type="hidden" name="container_type" value="<?cs var:html_escape(Data.Plugins.format_fs.container_type) ?>" />
<input type="hidden" name="store" value="step2" />
<button type="submit"><?cs var:html_escape(Lang.Plugins.format_fs.Button.Format) ?></button>
</form>
<?cs /if ?>
<?cs include:Settings.TemplateDir + "/show_volume_footer.cs" ?>

View file

@ -3,6 +3,9 @@ import os
class logs(CryptoBoxPlugin.CryptoBoxPlugin): class logs(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "system" ]
requestAuth = False
def doAction(self): def doAction(self):
self.__prepareFormData() self.__prepareFormData()
return "show_log" return "show_log"

View file

@ -1,18 +1,22 @@
<?cs # $Id$ ?> <?cs # $Id$ ?>
<style type="text/css">
input.ipnum { text-align: center }
</style>
<h1><?cs var:html_escape(Lang.Plugins.network.Title.Network) ?></h1> <h1><?cs var:html_escape(Lang.Plugins.network.Title.Network) ?></h1>
<?cs call:print_form_header("plugins/network") ?> <?cs call:print_form_header("plugins/network") ?>
<p><label for="ip"><?cs var:html_escape(Lang.Plugins.network.Text.IP) ?>: </label><br/> <p><label for="ip"><?cs var:html_escape(Lang.Plugins.network.Text.IP) ?>: </label>
<input type="text" tabindex="1" name="ip1" size="3" id="ip" value="<?cs <input class="ipnum" type="text" tabindex="1" name="ip1" size="3" id="ip"
var:Data.Plugins.network.ip.oc1 ?>" />. value="<?cs var:Data.Plugins.network.ip.oc1
<input type="text" tabindex="1" name="ip2" size="3" value="<?cs ?>" />.<input class="ipnum" type="text" tabindex="2" name="ip2" size="3"
var:Data.Plugins.network.ip.oc2 ?>" />. value="<?cs var:Data.Plugins.network.ip.oc2
<input type="text" tabindex="2" name="ip3" size="3" value="<?cs ?>" />.<input class="ipnum" type="text" tabindex="3" name="ip3" size="3"
var:Data.Plugins.network.3p.oc3 ?>" />. value="<?cs var:Data.Plugins.network.ip.oc3
<input type="text" tabindex="4" name="ip4" size="3" value="<?cs ?>" />.<input class="ipnum" type="text" tabindex="4" name="ip4" size="3"
var:Data.Plugins.network.ip.oc4 ?>" /></p> value="<?cs var:Data.Plugins.network.ip.oc4 ?>" /></p>
<input type="hidden" tabindex="5" name="store" value="yes" /> <input type="hidden" tabindex="5" name="store" value="yes" />

View file

@ -8,6 +8,9 @@ CHANGE_IP_DELAY=5
class network(CryptoBoxPlugin.CryptoBoxPlugin): class network(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "system" ]
requestAuth = True
def doAction(self, store=None, redirected="", ip1="", ip2="", ip3="", ip4=""): def doAction(self, store=None, redirected="", ip1="", ip2="", ip3="", ip4=""):
## if we were redirected, then we should display the default page ## if we were redirected, then we should display the default page
if redirected == "1": if redirected == "1":

View file

@ -5,7 +5,8 @@ Rank = 80
Title.Partition = Disk partitions Title.Partition = Disk partitions
Button { Button {
SelectDevice = Repartition disk SelectDevice = Manual partitioning
EasySetup = Automatic setup
AddPartition = Add AddPartition = Add
DelPartition = Remove DelPartition = Remove
SavePartitions = Write new partition table SavePartitions = Write new partition table
@ -24,8 +25,9 @@ Text {
PartType = Type PartType = Type
Size = Size (MB) Size = Size (MB)
SelectDevice = Choose a disk for partitioning SelectDevice = Choose a disk for partitioning
WarningMessage = If you continue, you will destroy all data on the choosen disk. Please be careful! WarningMessage = If you continue, you will destroy all data on the choosen disk. Please be VERY careful!
ProgressInfo = Progress of formatting: ProgressInfo = Progress of formatting:
CreateConfigPartition = create config partition
} }
SuccessMessage { SuccessMessage {
@ -33,6 +35,12 @@ SuccessMessage {
Title = Partitioning complete Title = Partitioning complete
Text = The disk was partitioned successfully. Text = The disk was partitioned successfully.
} }
EasySetup {
Title = Initialization completed
Text = Automatic initialization was finished successfully.
}
} }
WarningMessage { WarningMessage {

View file

@ -6,6 +6,9 @@ import CryptoBoxPlugin
class partition(CryptoBoxPlugin.CryptoBoxPlugin): class partition(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "system" ]
requestAuth = True
PartTypes = { PartTypes = {
"windows" : ["0xC", "vfat"], "windows" : ["0xC", "vfat"],
"linux" : ["L", "ext3"]} "linux" : ["L", "ext3"]}
@ -22,21 +25,29 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
## retrieve some values from 'args' - defaults are empty ## retrieve some values from 'args' - defaults are empty
self.withConfigPartition = self.__isWithConfigPartition(args) self.withConfigPartition = self.__isWithConfigPartition(args)
self.device = self.__getSelectedDevice(args) self.device = self.__getSelectedDevice(args)
self.cbox.log.debug("partition plugin: selected device=%s" % str(self.device))
self.deviceSize = self.__getAvailableDeviceSize(self.device) self.deviceSize = self.__getAvailableDeviceSize(self.device)
try: try:
step = args["step"] step = args["step"]
del args["step"] del args["step"]
except KeyError: except KeyError:
step = "select_device" step = "select_device"
try:
## this way of selecting the easy setup is necessary: see select_device.py for details
if args["easy"]: step = "easy"
except KeyError:
pass
## no (or invalid) device was supplied ## no (or invalid) device was supplied
if not self.device: if not self.device:
step == "select_device" step == "select_device"
if step == "add_partition": if step == "add_partition":
return self.__actionAddPartition(args) return self.__actionAddPartition(args)
if step == "del_partition": elif step == "del_partition":
return self.__actionDelPartition(args) return self.__actionDelPartition(args)
elif step == "finish": elif step == "finish":
return self.__actionFinish(args) return self.__actionFinish(args)
elif step == "easy":
return self.__actionEasySetup(args)
else: # for "select_device" and for invalid targets else: # for "select_device" and for invalid targets
return self.__actionSelectDevice(args) return self.__actionSelectDevice(args)
@ -132,11 +143,6 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed" self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
return self.__actionAddPartition(args) return self.__actionAddPartition(args)
else: else:
# TODO: will we use the "yield"-style? If yes, then remove these messages (success and warning)
#if self.__formatPartitions(parts):
# self.hdf["Data.Success"] = "Plugins.partition.Partitioned"
#else:
# self.hdf["Data.Warning"] = "Plugins.partition.FormattingFailed"
""" """
tricky problem: if the device was partitioned, then a created config partition is still part of the containerlist, as the label is not checked again - very ugly!!! So we will call reReadContainerList after formatting the last partition - see below tricky problem: if the device was partitioned, then a created config partition is still part of the containerlist, as the label is not checked again - very ugly!!! So we will call reReadContainerList after formatting the last partition - see below
""" """
@ -156,7 +162,10 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
## important: reRead the containerList ## important: reRead the containerList
self.cbox.reReadContainerList() self.cbox.reReadContainerList()
## return the result ## return the result
yield result if result:
yield "OK"
else:
yield "<b>Error</b>"
return { return {
"template": "show_format_progress", "template": "show_format_progress",
"generator": result_generator} "generator": result_generator}
@ -164,6 +173,28 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
return self.__actionAddPartition(args) return self.__actionAddPartition(args)
def __actionEasySetup(self, args):
import types
## we do not have to take special care for a possible config partition
parts = [ { "size": self.deviceSize, "type": "windows" } ]
## doe
if not self.__runFDisk(parts):
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
return None
result = [e for e in self.__formatPartitions(parts) if type(e) == types.BooleanType] # it is a generator, returning device names and bolean values
## check if there is a "False" return value
if False in result:
## operation failed
self.hdf["Data.Warning"] = "Plugins.partition.FormattingFailed"
self.cbox.log.info("easy partitioning failed")
return None
else:
## operation was successful
self.hdf["Data.Success"] = "Plugins.partition.EasySetup"
self.cbox.log.info("easy partitioning succeeded")
return None
def __setPartitionData(self, parts): def __setPartitionData(self, parts):
availSize = self.deviceSize availSize = self.deviceSize
i = 0 i = 0
@ -242,6 +273,7 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
## check if the device is completely filled (to avoid some empty last blocks) ## check if the device is completely filled (to avoid some empty last blocks)
avail_size = self.deviceSize avail_size = self.deviceSize
for d in parts: avail_size -= d["size"] for d in parts: avail_size -= d["size"]
self.cbox.log.debug("remaining size: %d" % avail_size)
isFilled = avail_size == 0 isFilled = avail_size == 0
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
@ -252,7 +284,7 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
self.cbox.prefs["Programs"]["super"], self.cbox.prefs["Programs"]["super"],
self.cbox.prefs["Programs"]["CryptoBoxRootActions"], self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin", "plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"), os.path.join(self.pluginDir, "root_action.py"),
"partition", "partition",
self.device]) self.device])
for line in self.__getSFDiskLayout(parts, isFilled): for line in self.__getSFDiskLayout(parts, isFilled):
@ -263,12 +295,18 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
def __getSFDiskLayout(self, paramParts, isFilled): def __getSFDiskLayout(self, paramParts, isFilled):
"""this generator returns the input lines for sfdisk"""
parts = paramParts[:] parts = paramParts[:]
## first a (possible) configuration partition - so it will be reusable ## first a (possible) configuration partition - so it will be reusable
if self.withConfigPartition: if self.withConfigPartition:
## fill the main table (including a config partition) ## fill the main table (including a config partition)
yield ",%d,%s" % (self.ConfigPartition["size"], self.ConfigPartition["type"]) yield ",%d,%s" % (self.ConfigPartition["size"], self.ConfigPartition["type"])
## one primary partition ## one primary partition
if isFilled and (len(parts) == 1):
## fill the rest of the device
yield ",,%s,*" % self.PartTypes[parts[0]["type"]][0]
else:
## only use the specified size
yield ",%d,%s,*" % (parts[0]["size"], self.PartTypes[parts[0]["type"]][0]) yield ",%d,%s,*" % (parts[0]["size"], self.PartTypes[parts[0]["type"]][0])
del parts[0] del parts[0]
## no extended partition, if there is only one disk ## no extended partition, if there is only one disk
@ -303,10 +341,7 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
partType = self.PartTypes[parts[0]["type"]][1] partType = self.PartTypes[parts[0]["type"]][1]
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, partType)) self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, partType))
yield dev_name yield dev_name
if self.__formatOnePartition(dev_name, partType): yield self.__formatOnePartition(dev_name, partType)
yield "OK"
else:
yield "<b>Failed!</b>"
del parts[0] del parts[0]
## other data partitions ## other data partitions
part_num = 5 part_num = 5
@ -315,10 +350,7 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
partType = self.PartTypes[parts[0]["type"]][1] partType = self.PartTypes[parts[0]["type"]][1]
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, partType)) self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, partType))
yield dev_name yield dev_name
if self.__formatOnePartition(dev_name, partType): yield self.__formatOnePartition(dev_name, partType)
yield "OK"
else:
yield "<b>Failed!</b>"
part_num += 1 part_num += 1
del parts[0] del parts[0]
return return
@ -331,7 +363,7 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
self.cbox.prefs["Programs"]["super"], self.cbox.prefs["Programs"]["super"],
self.cbox.prefs["Programs"]["CryptoBoxRootActions"], self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin", "plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"), os.path.join(self.pluginDir, "root_action.py"),
"format", "format",
dev_name, dev_name,
type]) type])
@ -352,7 +384,7 @@ class partition(CryptoBoxPlugin.CryptoBoxPlugin):
self.cbox.prefs["Programs"]["super"], self.cbox.prefs["Programs"]["super"],
self.cbox.prefs["Programs"]["CryptoBoxRootActions"], self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin", "plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"), os.path.join(self.pluginDir, "root_action.py"),
"label", "label",
dev_name, dev_name,
label]) label])

View file

@ -15,7 +15,7 @@
<?cs /each ?> <?cs /each ?>
</select></p> </select></p>
<p><label for="create_config_partition">Create configuration partition?</label><input type="checkbox" name="create_config_partition" value="1" tabindex="2" id="create_config_partition" /></p> <p><input type="checkbox" name="create_config_partition" value="1" tabindex="2" id="create_config_partition" /><label for="create_config_partition"><?cs var:html_escape(Lang.Plugins.partition.Text.CreateConfigPartition) ?></label></p>
<!-- <!--
<?cs if:Data.Plugins.partition.CreateConfigPartition ?> <?cs if:Data.Plugins.partition.CreateConfigPartition ?>
<input type="hidden" name="create_config_partition" value="1" /> <input type="hidden" name="create_config_partition" value="1" />
@ -28,7 +28,13 @@
<input type="hidden" name="step" value="add_partition" /> <input type="hidden" name="step" value="add_partition" />
<button type="submit" tabindex="3"><?cs var:html_escape(Lang.Plugins.partition.Button.SelectDevice) ?></button> <div align="center"><table><tr>
<!-- we have to avoid an ugly IE bug, that ignores the "value" attribute
of "button" elements: if a variable called 'easy' is set, then this
button was choosen - uuuuuugly! -->
<td><button type="submit" name="easy" value="1" tabindex="3"><?cs var:html_escape(Lang.Plugins.partition.Button.EasySetup) ?></button></td>
<td><button type="submit" name="normal" value="1" tabindex="4"><?cs var:html_escape(Lang.Plugins.partition.Button.SelectDevice) ?></button></td>
</tr></table></div>
</form> </form>

View file

@ -5,34 +5,49 @@ The following directory structure is required:
Python code interface: Python code interface:
- create a class with the same name as the plugin - it has to inherit CryptoBoxPlugin - create a class with the same name as the plugin - it must inherit CryptoBoxPlugin
- function "doAction": - function "doAction":
- this function will get called whenever this plugins is involved in a request - this function will get called whenever this plugins is involved in a request
- all arguments should be optional (e.g. for displaying a form without previous input values) - all arguments should be optional (e.g. for displaying a form without previous input values)
- the argument "store" should be used to process a form submission (just a recommendation) - the argument "store" should be used to process a form submission (just a recommendation)
- if the processing failed for some reason (invalid input, ...), it should manually set the "Data.Warning" (resp. "Data.Error" or "Data.Success") to a value of your choice (preferably you may want to use messages of your namespace (e.g. "Plugins.PLUGINNAME.InvalidInput")) - if the processing failed for some reason (invalid input, ...), it should manually set the
- the return value should be the name of the template that should be displayed after processing (a template file in the plugin directory takes precedence over global template files) "Data.Warning" (resp. "Data.Error" or "Data.Success") to a value of your choice (preferably
you may want to use messages of your namespace (e.g. "Plugins.PLUGINNAME.InvalidInput"))
- the return value should be the name of the template that should be displayed after processing
(a template file in the plugin directory takes precedence over global template files)
- the return value may also be a dictionary with the following elements: - the return value may also be a dictionary with the following elements:
* template: the name of the template file (mandatory) * template: the name of the template file (mandatory)
* generator: a generator object ("yield") - its content will replace every occourence of "<!-- CONTENT_DUMMY -->" in the template (useful for pages that are displayed step by step (as for formatting of filesystems)) * generator: a generator object ("yield") - its content will replace every
- an empty (e.g. None) return value can be used to go return to the plugin page occurrence of "<!-- CONTENT_DUMMY -->" in the template (useful for pages that
are displayed step by step (as for formatting of filesystems))
- an empty (e.g. None) return value can be used to go to the default page (now: the
plugin overview)
- function "getStatus": - function "getStatus":
- returns a string, that describes a state connected to this plugin (e.g. the current date and time (for the "date" plugin)) - returns a string, that describes a state connected to this plugin (e.g. the current date and
time (for the "date" plugin))
- the class variable "pluginCapabilities" must be an array of strings (supported: "system" and
"volume")
- the class variable "requestAuth" is boolean and defines, if admin authentication is necessary
for this plugin
- volume plugins contain the attribute "device" (you may trust this value - a volume plugin will
never get called with an invalid device)
Language file structure: Language file structure:
- the content of the language file will be added to the hdf dataset below "Lang.Plugins.PLUGINNAME" (this avoids namespace conflicts) - the content of the language file will be added to the hdf dataset below "Lang.Plugins.PLUGINNAME"
(this avoids namespace conflicts)
- the following values _must_ be defined: - the following values _must_ be defined:
Name (a short description) Name (a short description)
Link (the visible text for links to this plugin) Link (the visible text for links to this plugin)
Rank (defines the order of the plugins displayed (0..100)) Rank (defines the order of the plugins displayed (0..100))
- all warnings, error and success messages should be stored below WarningMessage.??? (resp. ErrorMessage or SuccessMessage) - all warnings, error and success messages should be stored below WarningMessage.???
(resp. ErrorMessage or SuccessMessage)
Clearsilver template: Clearsilver template:
- should start with a "<h1>" tag - should start with a "<h1>" tag (volume plugins: "h2")
- links to the plugin (e.g. in form headers) could look like the following: - links to the plugin (e.g. in form headers) could look like the following:
<?cs call:link("plugins/PLUGINNAME",'','','','') ?> <?cs call:link("plugins/PLUGINNAME",'','','','') ?>
- a hidden input field called "store" should be used to indicate a form submission - volume plugins must include "show_volume_[header|footer]" (see examples)

View file

@ -0,0 +1,27 @@
<?cs # $Id$ ?>
<h1><?cs var:html_escape(Lang.Plugins.shutdown.Title.Shutdown) ?></h1>
<p style="text-align: center">
<?cs var:html_escape(Lang.Plugins.shutdown.Text.ShutdownInfo) ?>
</p>
<table style="text-align:center; width:100%">
<tr>
<td style="text-align: right">
<?cs call:print_form_header("plugins/shutdown") ?>
<input type="hidden" name="type" value="reboot" />
<button type="submit" tabindex="2"><?cs var:html_escape(Lang.Plugins.shutdown.Button.Reboot) ?></button>
</form>
</td>
<td style="width:5%"></td>
<td style="text-align: left">
<?cs call:print_form_header("plugins/shutdown") ?>
<input type="hidden" name="type" value="shutdown" />
<button type="submit" tabindex="1"><?cs var:html_escape(Lang.Plugins.shutdown.Button.Shutdown) ?></button>
</form>
</td>
</tr>
</table>

View file

@ -0,0 +1,34 @@
Name = Shutdown or reboot the computer
Link = Shutdown/Reboot
Rank = 70
Title.Shutdown = Shutdown computer
Button.Shutdown = Poweroff
Button.Reboot = Reboot
Text.ShutdownInfo = You may turn off or reboot your CryptoBox here.
SuccessMessage {
Shutdown {
Title = Shutting down the system
Text = If the computer does not turn off itself within a minute, then you should plug it off manually.
}
Reboot {
Title = Rebooting the system
Text = This may take a while (depending on your hardware) ...
}
}
WarningMessage {
ShutdownFailed {
Title = Shutdown failed
Text = Shutting down of the system failed for some reason - sorry!
}
RebootFailed {
Title = Reboot failed
Text = Reboot of the system failed for some reason - sorry!
}
}

View file

@ -0,0 +1,48 @@
#!/usr/bin/env python2.4
## necessary: otherwise CryptoBoxRootActions.py will refuse to execute this script
PLUGIN_TYPE = "cryptobox"
POWEROFF_BIN = "/sbin/poweroff"
REBOOT_BIN = "/sbin/reboot"
import subprocess
import re
import sys
import os
def call_prog(progy):
proc = subprocess.Popen(
shell = False,
args = [progy])
proc.communicate()
return proc.returncode == 0
if __name__ == "__main__":
args = sys.argv[1:]
self_bin = sys.argv[0]
if len(args) > 1:
sys.stderr.write("%s: too many arguments (%s)\n" % (self_bin, args))
sys.exit(1)
if len(args) == 0:
sys.stderr.write("%s: no argument supplied\n" % self_bin)
sys.exit(1)
if args[0] == "reboot":
result = call_prog(REBOOT_BIN)
elif args[0] == "shutdown":
result = call_prog(POWEROFF_BIN)
else:
sys.stderr.write("%s: illegal argument (%s)\n" % (self_bin, args[0]))
sys.exit(1)
if result:
sys.exit(0)
else:
sys.exit(1)

View file

@ -0,0 +1,50 @@
import CryptoBoxPlugin
REDIRECT_DELAY = 180
class shutdown(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "system" ]
requestAuth = False
def doAction(self, type=None):
if not type:
return "form_shutdown"
elif type == "shutdown":
if self.__doShutdown("shutdown"):
self.hdf["Data.Success"] = "Plugins.shutdown.Shutdown"
return None
else:
self.hdf["Data.Warning"] = "Plugins.shutdown.ShutdownFailed"
return "form_shutdown"
elif type == "reboot":
if self.__doShutdown("reboot"):
self.hdf["Data.Success"] = "Plugins.shutdown.Reboot"
self.hdf["Data.Redirect.URL"] = ""
self.hdf["Data.Redirect.Delay"] = REDIRECT_DELAY
return None
else:
self.hdf["Data.Warning"] = "Plugins.shutdown.RebootFailed"
return "form_shutdown"
else:
return "form_shutdown"
def getStatus(self):
return "the box is up'n'running"
def __doShutdown(self, action):
import subprocess
import os
proc = subprocess.Popen(
shell = False,
args = [
self.cbox.prefs["Programs"]["super"],
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin",
os.path.join(self.pluginDir, "root_action.py"),
action])
proc.communicate()
return proc.returncode == 0

View file

@ -0,0 +1,21 @@
Name = Technical details of a volume
Link = Details
Rank = 100
Title.Details = Technical details
Text {
DeviceName = Name of device
Status = Status
StatusActive = active
StatusPassive = passive
EncryptionStatus = Encryption
Yes = Yes
No = No
Size {
All = Space of volume
Avail = Available space of volume
Used = Used space of volume
}
}

View file

@ -0,0 +1,19 @@
<?cs # $Id$ ?>
<?cs include:Settings.TemplateDir + "/show_volume_header.cs" ?>
<h2><?cs var:html_escape(Lang.Plugins.volume_details.Title.Details) ?></h2>
<p><ul>
<li><?cs var:html_escape(Lang.Text.ContainerName) ?>: <?cs var:html_escape(Data.CurrentDisk.name) ?></li>
<li><?cs var:html_escape(Lang.Plugins.volume_details.Text.DeviceName) ?>: <?cs var:html_escape(Data.CurrentDisk.device) ?></li>
<li><?cs var:html_escape(Lang.Plugins.volume_details.Text.Status) ?>: <?cs if:Data.CurrentDisk.active ?><?cs var:html_escape(Lang.Plugins.volume_details.Text.StatusActive) ?><?cs else ?><?cs var:html_escape(Lang.Plugins.volume_details.Text.StatusPassive) ?><?cs /if ?></li>
<li><?cs var:html_escape(Lang.Plugins.volume_details.Text.EncryptionStatus) ?>: <?cs if:Data.CurrentDisk.encryption ?><?cs var:html_escape(Lang.Plugins.volume_details.Text.Yes) ?><?cs else ?><?cs var:html_escape(Lang.Plugins.volume_details.Text.Yes) ?><?cs /if ?></li>
<?cs if:Data.CurrentDisk.active ?>
<li><?cs var:html_escape(Lang.Plugins.volume_details.Text.Size.All) ?>: <?cs var:html_escape(Data.CurrentDisk.capacity.size) ?></li>
<li><?cs var:html_escape(Lang.Plugins.volume_details.Text.Size.Avail) ?>: <?cs var:html_escape(Data.CurrentDisk.capacity.free) ?></li>
<li><?cs var:html_escape(Lang.Plugins.volume_details.Text.Size.Used) ?>: <?cs var:html_escape(Data.CurrentDisk.capacity.percent) ?>%</li>
<?cs /if ?>
</ul></p>
<?cs include:Settings.TemplateDir + "/show_volume_footer.cs" ?>

View file

@ -0,0 +1,17 @@
import CryptoBoxPlugin
class volume_details(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "volume" ]
requestAuth = False
def doAction(self):
## all variables are already set somewhere else
return "volume_details"
def getStatus(self):
return "no status"

View file

@ -0,0 +1,57 @@
Name = Mount and umount volumes
Link = Main
Rank = 0
Title {
Mount = Activate volume
Umount = Deactivate volume
}
Button {
Mount = Activate volume
Umount = Deactivate volume
}
SuccessMessage {
MountDone {
Title = Encrypted filesystem activated
Text = The encrypted filesystem is now available.
}
UmountDone {
Title = Encrypted filesystem deactivated
Text = The encrypted filesystem is now secured from all forms of access.
}
}
WarningMessage {
MountFailed {
Title = Activation failed
Text = The encrypted filesystem could not be activated. Probably the given password was wrong. Please try again.
}
MountCryptoFailed {
Title = Activation failed
Text = Maybe you entered the wrong password?
}
UmountFailed {
Title = Deactivation failed
Text = The encrypted filesystem could not be deactivated. Probably some files are still in use. Close all unclean programs (for example that widely used word processor). In case of emergency just shut down the CryptoBox!
}
IsAlreadyMounted {
Title = Already active
Text = The volume is already active.
}
IsNotMounted {
Title = Inactive
Text = The volume is currently not active.
}
}

View file

@ -0,0 +1,16 @@
<h2><?cs var:html_escape(Lang.Plugins.volume_mount.Title.Mount) ?></h2>
<p><?cs call:print_form_header("plugins/volume_mount") ?>
<input type="hidden" name="device" value="<?cs var:html_escape(Data.CurrentDisk.device) ?>" />
<?cs if:Data.CurrentDisk.encryption ?>
<input type="hidden" name="action" value="mount_luks" />
<?cs else ?>
<input type="hidden" name="action" value="mount_plain" />
<?cs /if ?>
<?cs if:Data.CurrentDisk.encryption ?>
<label for="pw"><?cs var:html_escape(Lang.Text.EnterCurrentCryptoPassword) ?>: </label>
<input type="password" tabindex="1" id="pw" name="pw" size="20" maxlength="60" />
<?cs /if ?>
<button type="submit" tabindex="2"><?cs var:html_escape(Lang.Plugins.volume_mount.Button.Mount) ?></button>
</form></p>

View file

@ -0,0 +1,102 @@
import CryptoBoxPlugin
from CryptoBoxExceptions import *
class volume_mount(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "volume" ]
requestAuth = False
def doAction(self, action=None, pw=None):
self.container = self.cbox.getContainer(self.device)
if action == "mount_plain":
return self.__doMountPlain()
elif action == "mount_luks":
return self.__doMountLuks(pw)
elif action == "umount":
return self.__doUmount()
elif not action:
return "volume_status"
else:
self.cbox.log.info("plugin 'volume_mount' - unknown action: %s" % action)
return None
def getStatus(self):
container = self.cbox.getContainer(self.device)
if not self.container:
return "invalid device"
if container.isMounted():
return "active"
else:
return "passive"
def __doMountPlain(self):
if self.container.isMounted():
self.hdf["Data.Warning"] = "Plugins.volume_mount.IsAlreadyMounted"
self.cbox.log.info("the device (%s) is already mounted" % device)
return "volume_status"
if self.container.getType() != self.container.Types["plain"]:
## not a plain container - fail silently
self.cbox.log.info("plugin 'volume_mount' - invalid container type")
return "volume_status"
try:
self.container.mount()
except CBMountError, errMsg:
self.hdf["Data.Warning"] = "Plugins.volume_mount.MountFailed"
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, errMsg))
return "volume_status"
except CBContainerError, errMsg:
self.hdf["Data.Warning"] = "Plugins.volume_mount.MountFailed"
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, errMsg))
return "volume_status"
self.cbox.log.info("successfully mounted the volume: %s" % self.device)
self.hdf["Data.Success"] = "Plugins.volume_mount.MountDone"
return "volume_status"
def __doMountLuks(self, pw):
if self.container.isMounted():
self.hdf["Data.Warning"] = "Plugins.volume_mount.IsAlreadyMounted"
self.cbox.log.info("the device (%s) is already mounted" % device)
return "volume_status"
if not pw:
self.dataset["Data.Warning"] = "EmptyCryptoPassword"
self.log.info("no password was supplied for mounting of device: '%s'" % device)
return "volume_status"
if self.container.getType() != self.container.Types["luks"]:
## not a luks container - fail silently
self.cbox.log.info("plugin 'volume_mount' - invalid container type")
return "volume_status"
try:
self.container.mount(pw)
except CBMountError, errMsg:
self.hdf["Data.Warning"] = "Plugins.volume_mount.MountCryptoFailed"
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, errMsg))
return "volume_status"
except CBContainerError, errMsg:
self.hdf["Data.Warning"] = "Plugins.volume_mount.MountCryptoFailed"
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, errMsg))
return "volume_status"
self.cbox.log.info("successfully mounted the volume: %s" % self.device)
self.hdf["Data.Success"] = "Plugins.volume_mount.MountDone"
return "volume_status"
def __doUmount(self):
if not self.container.isMounted():
self.hdf["Data.Warning"] = "Plugins.volume_mount.IsNotMounted"
self.cbox.log.info("the device (%s) is currently not mounted" % self.device)
return "volume_status"
try:
self.container.umount()
except CBUmountError, errMsg:
self.hdf["Data.Warning"] = "InvalidType"
self.cbox.log.warn("could not umount the volume (%s): %s" % (self.device, errMsg))
return "volume_status"
self.cbox.log.info("successfully unmounted the container: %s" % self.device)
self.hdf["Data.Success"] = "Plugins.volume_mount.UmountDone"
return "volume_status"

View file

@ -0,0 +1,9 @@
<?cs include:Settings.TemplateDir + "/show_volume_header.cs" ?>
<?cs if:Data.CurrentDisk.active ?>
<?cs include:Settings.PluginDir + "/volume_mount/volume_umount.cs" ?>
<?cs else ?>
<?cs include:Settings.PluginDir + "/volume_mount/volume_mount.cs" ?>
<?cs /if ?>
<?cs include:Settings.TemplateDir + "/show_volume_footer.cs" ?>

View file

@ -0,0 +1,8 @@
<h2><?cs var:html_escape(Lang.Plugins.volume_mount.Title.Umount) ?></h2>
<?cs call:print_form_header("plugins/volume_mount") ?>
<p><input type="hidden" name="device" value="<?cs var:html_escape(Data.CurrentDisk.device) ?>" />
<input type="hidden" name="action" value="umount" />
<button type="submit" tabindex="2"><?cs var:html_escape(Lang.Button.Umount) ?></button></p>
</form>

View file

@ -0,0 +1,51 @@
Name = Volume properties
Link = Properties
Rank = 40
Title {
Properties = Properties
ChangeVolumeName = Change the name of this volume
ChangePassword = Change the password of this volume
}
Button {
ContainerNameSet = Change name
ChangePassword = Change password
}
Text {
UmountBeforeProps = You must deactivate a volume, if you want to change its properties.
}
SuccessMessage {
PasswordChange {
Title = Password changed
Text = The password of this volume was changed successfully.
}
}
WarningMessage {
InvalidVolumeName {
Title = Changing of container's name failed
Text = The supplied new name of the container was invalid. Please try again!
}
SetVolumeNameFailed {
Title = Changing of container's name failed
Text = Could not change the name of the container. Take a look at the log files for details.
}
VolumeNameIsInUse {
Title = Volume name is in use
Text = Another volume with the same name is active.
}
PasswordChange {
Title = Could not change password
Text = The password of this volume could not be changed - sorry!
}
}

View file

@ -0,0 +1,63 @@
<?cs # $Id$ ?>
<?cs include:Settings.TemplateDir + "/show_volume_header.cs" ?>
<h2><?cs var:html_escape(Lang.Plugins.volume_props.Title.Properties) ?></h2>
<?cs if:Data.CurrentDisk.active ?>
<div class="unavailable_action">
<?cs var:html_escape(Lang.Plugins.volume_props.Text.UmountBeforeProps) ?>
</div>
<?cs else ?>
<table>
<?cs # name change is only possible if the volume is not mounted ?>
<tr><td colspan="3">
<h3><?cs var:html_escape(Lang.Plugins.volume_props.Title.ChangeVolumeName) ?></h3>
</td></tr>
<?cs call:print_form_header("plugins/volume_props") ?><tr>
<td align="right"><label for="vol_name"><?cs var:html_escape(Lang.Text.ContainerName) ?>: </label></td>
<td><input type="text" name="vol_name" tabindex="10" size="15" id="vol_name" value="<?cs var:html_escape(Data.CurrentDisk.name) ?>" /></td>
<td align="right">
<input type="hidden" name="device" value="<?cs var:html_escape(Data.CurrentDisk.device) ?>" />
<input type="hidden" name="store" value="set_name" />
<button type="submit" tabindex="11"><?cs var:html_escape(Lang.Plugins.volume_props.Button.ContainerNameSet) ?></button>
</td>
</tr></form>
<tr><td></td><td></td><td></td></tr>
<?cs # password change is only possible if the volume is not mounted ?>
<tr><td colspan="3">
<h3><?cs var:html_escape(Lang.Plugins.volume_props.Title.ChangePassword) ?></h3>
</td></tr>
<?cs call:print_form_header("plugins/volume_props") ?>
<tr>
<td align="right"><label for="old_pw"><?cs var:html_escape(Lang.Text.EnterCurrentCryptoPassword) ?>: </label></td>
<td><input type="password" name="old_pw" tabindex="20" size="15" id="old_pw" /></td>
<td></td>
</tr>
<tr>
<td align="right"><label for="new_pw"><?cs var:html_escape(Lang.Text.EnterNewCryptoPassword) ?>: </label></td>
<td><input type="password" name="new_pw" tabindex="21" size="15" id="new_pw" /></td>
<td></td>
</tr>
<tr>
<td align="right"><label for="new_pw2"><?cs var:html_escape(Lang.Text.EnterSameCryptoPassword) ?>: </label></td>
<td><input type="password" name="new_pw2" tabindex="22" size="15" id="new_pw2" /></td>
<td align="right">
<input type="hidden" name="device" value="<?cs var:html_escape(Data.CurrentDisk.device) ?>" />
<input type="hidden" name="store" value="change_pw" />
<button type="submit" tabindex="23"><?cs var:html_escape(Lang.Plugins.volume_props.Button.ChangePassword) ?></button></p>
</td>
</tr>
</form>
<tr><td></td><td></td><td></td></tr>
</table>
<?cs /if ?>
<?cs include:Settings.TemplateDir + "/show_volume_footer.cs" ?>

View file

@ -0,0 +1,80 @@
import CryptoBoxPlugin
from CryptoBoxExceptions import *
class volume_props(CryptoBoxPlugin.CryptoBoxPlugin):
pluginCapabilities = [ "volume" ]
requestAuth = False
def doAction(self, store=None, vol_name=None, old_pw=None, new_pw=None, new_pw2=None):
self.container = self.cbox.getContainer(self.device)
if not self.container:
return None
self.__prepareHDF()
if store == "set_name":
return self.__setVolumeName(vol_name)
elif store == "change_pw":
return self.__changePassword(old_pw, new_pw, new_pw2)
elif not store:
return "volume_properties"
else:
self.cbox.log.info("plugin 'volume_props' - unknown action: %s" % store)
return "volume_properties"
def getStatus(self):
self.container = self.cbox.getContainer(self.device)
if not self.container:
return "invalid device"
return "name=%s" % self.container.getName()
def __prepareHDF(self):
self.hdf[self.hdf_prefix + "vol_name"] = self.container.getName()
def __setVolumeName(self, vol_name):
if not vol_name:
self.hdf["Data.Warning"] = "Plugins.volume_props.InvalidVolumeName"
return "volume_properties"
if vol_name == self.container.getName():
## nothing has to be done
return "volume_properties"
try:
self.container.setName(vol_name)
except CBInvalidName:
self.hdf["Data.Warning"] = "Plugins.volume_props.InvalidVolumeName"
except CBNameActivelyUsed:
self.hdf["Data.Warning"] = "Plugins.volume_props.VolumeNameIsInUse"
except CBContainerError:
self.hdf["Data.Warning"] = "Plugins.volume_props.SetVolumeNameFailed"
## reread the volume name
self.__prepareHDF()
return "volume_properties"
def __changePassword(self, old_pw, new_pw, new_pw2):
if not old_pw:
self.hdf["Data.Warning"] = "EmptyCryptoPassword"
elif not new_pw:
self.hdf["Data.Warning"] = "EmptyNewCryptoPassword"
elif new_pw != new_pw2:
self.hdf["Data.Warning"] = "DifferentCryptoPasswords"
elif old_pw == new_pw:
## do nothing
pass
else:
try:
self.container.changePassword(old_pw, new_pw)
except CBInvalidType, errMsg:
self.cbox.log.info("plugin 'volume_props' - cannot change passphrase for non-encrypted container (%s): %s" % (self.device, errMsg))
except CBVolumeIsActive:
self.hdf["Data.Warning"] = "VolumeMayNotBeMounted"
except CBChangePasswordError, errMsg:
self.cbox.log.warn("plugin 'volume_props' - cannot change password for device (%s): %s" % (self.device, errMsg))
self.hdf["Data.Warning"] = "Plugins.volume_props.PasswordChange"
else:
self.hdf["Data.Success"] = "Plugins.volume_props.PasswordChange"
return "volume_properties"