Skip to content

Commit

Permalink
storage: Checkboxes for common crypto and mount options
Browse files Browse the repository at this point in the history
  • Loading branch information
mvollmer committed Oct 19, 2017
1 parent 04e69cf commit 3729f86
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 63 deletions.
9 changes: 2 additions & 7 deletions pkg/storaged/crypto-tab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,18 +105,13 @@ var CryptoTab = React.createClass({
function edit_options() {
edit_config(function (config, commit) {
dialog.open({ Title: _("Encryption Options"),
Fields: [
{ TextInput: "options",
Title: _("Options"),
Value: old_options
}
],
Fields: FormatDialog.crypto_options_dialog_fields(old_options),
Action: {
Title: _("Apply"),
action: function (vals) {
config["options"] = {
t: 'ay',
v: utils.encode_filename(vals.options)
v: utils.encode_filename(FormatDialog.crypto_options_dialog_options(vals))
}
return commit();
}
Expand Down
175 changes: 148 additions & 27 deletions pkg/storaged/format-dialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,144 @@ var StorageControls = require("./storage-controls.jsx");

var _ = cockpit.gettext;

function parse_options(options) {
if (options)
return (options.split(",")
.map(function (s) { return s.trim() })
.filter(function (s) { return s != "" }));
else
return [ ];
}

function unparse_options(split) {
return split.join(",");
}

function extract_option(split, opt) {
var index = split.indexOf(opt);
if (index >= 0) {
split.splice(index, 1);
return true;
} else {
return false;
}
}

function mounting_dialog_fields(is_custom, mount_dir, mount_options, visible) {

if (!visible)
visible = function () { return true; };

var split_options = parse_options(mount_options == "defaults" ? "" : mount_options);
var opt_auto = !extract_option(split_options, "noauto");
var opt_ro = extract_option(split_options, "ro");
var extra_options = unparse_options(split_options);

return [
{ SelectOne: "mounting",
Title: _("Mounting"),
Options: [
{ value: "default", Title: _("Default"), selected: !is_custom },
{ value: "custom", Title: _("Custom"), selected: is_custom }
],
visible: visible
},
{ TextInput: "mount_point",
Title: _("Mount Point"),
Value: mount_dir,
visible: function (vals) {
return visible(vals) && vals.mounting == "custom";
},
validate: function (val) {
if (val.trim() == "")
return _("Mount point can not be empty");
}
},
{ RowTitle: _("Mount options"),
CheckBox: "mount_auto",
Title: _("Mount at boot"),
Value: opt_auto,
visible: function (vals) {
return visible(vals) && vals.mounting == "custom";
},
update: function (vals, trigger) {
if (trigger == "crypto_options_auto" && vals.crypto_options_auto == false)
return false;
else
return vals.mount_auto;
}
},
{ CheckBox: "mount_ro",
Title: _("Mount read only"),
Value: opt_ro,
visible: function (vals) {
return visible(vals) && vals.mounting == "custom";
},
update: function (vals, trigger) {
if (trigger == "crypto_options_ro" && vals.crypto_options_ro == true)
return true;
else
return vals.mount_ro;
}
},
{ CheckBoxText: "mount_extra_options",
Title: _("Custom mount options"),
Value: extra_options == "" ? false : extra_options,
visible: function (vals) {
return visible(vals) && vals.mounting == "custom";
}
}
];
}

function mounting_dialog_options(vals) {
var opts = [ ];
if (!vals.mount_auto)
opts.push("noauto");
if (vals.mount_ro)
opts.push("ro");
if (vals.mount_extra_options !== false)
opts = opts.concat(parse_options(vals.mount_extra_options));
return unparse_options(opts);
}

function crypto_options_dialog_fields(options, visible) {
var split_options = parse_options(options);
var opt_auto = !extract_option(split_options, "noauto");
var opt_ro = extract_option(split_options, "readonly");
var extra_options = unparse_options(split_options);

return [
{ RowTitle: _("Encryption Options"),
CheckBox: "crypto_options_auto",
Title: _("Unlock at boot"),
Value: opt_auto,
visible: visible
},
{ CheckBox: "crypto_options_ro",
Title: _("Unlock read only"),
Value: opt_ro,
visible: visible
},
{ CheckBoxText: "crypto_extra_options",
Title: _("Custom encryption options"),
Value: extra_options == "" ? false : extra_options,
visible: visible
}
];
}

function crypto_options_dialog_options(vals) {
var opts = [ ];
if (!vals.crypto_options_auto)
opts.push("noauto");
if (vals.crypto_options_ro)
opts.push("readonly");
if (vals.crypto_extra_options !== false)
opts = opts.concat(parse_options(vals.crypto_extra_options));
return unparse_options(opts);
}

function format_dialog(client, path, start, size, enable_dos_extended) {
var block = client.blocks[path];
var block_ptable = client.blocks_ptable[path];
Expand Down Expand Up @@ -172,32 +310,9 @@ function format_dialog(client, path, start, size, enable_dos_extended) {
{ CheckBox: "store_passphrase",
Title: _("Store passphrase"),
visible: is_encrypted_and_not_old_udisks2
},
{ TextInput: "crypto_options",
Title: _("Encryption Options"),
visible: is_encrypted_and_not_old_udisks2
},
{ SelectOne: "mounting",
Title: _("Mounting"),
Options: [
{ value: "default", Title: _("Default") },
{ value: "custom", Title: _("Custom") }
],
visible: is_filesystem_and_not_old_udisks2
},
{ TextInput: "mount_point",
Title: _("Mount Point"),
visible: function (vals) {
return is_filesystem_and_not_old_udisks2(vals) && vals.mounting == "custom";
}
},
{ TextInput: "mount_options",
Title: _("Mount Options"),
visible: function (vals) {
return is_filesystem_and_not_old_udisks2(vals) && vals.mounting == "custom";
}
}
],
].concat(crypto_options_dialog_fields("", is_encrypted_and_not_old_udisks2))
.concat(mounting_dialog_fields(false, "", "", is_filesystem_and_not_old_udisks2)),
Action: {
Title: create_partition? _("Create partition") : _("Format"),
Danger: (create_partition?
Expand All @@ -216,23 +331,25 @@ function format_dialog(client, path, start, size, enable_dos_extended) {
options.label = { t: 's', v: vals.name };

var config_items = [ ];
var mount_options = mounting_dialog_options(vals);
if (vals.mounting == "custom")
config_items.push([
"fstab", {
dir: { t: 'ay', v: utils.encode_filename(vals.mount_point) },
type: { t: 'ay', v: utils.encode_filename("auto") },
opts: { t: 'ay', v: utils.encode_filename(vals.mount_options || "defaults") },
opts: { t: 'ay', v: utils.encode_filename(mount_options || "defaults") },
freq: { t: 'i', v: 0 },
passno: { t: 'i', v: 0 },
"track-parents": { t: 'b', v: true }
}]);

var crypto_options = crypto_options_dialog_options(vals);
if (is_encrypted(vals)) {
vals.type = vals.type.replace("luks+", "");
options["encrypt.passphrase"] = { t: 's', v: vals.passphrase };

var item = {
options: { t: 'ay', v: utils.encode_filename(vals.crypto_options) },
options: { t: 'ay', v: utils.encode_filename(crypto_options) },
"track-parents": { t: 'b', v: true }
};
if (vals.store_passphrase) {
Expand Down Expand Up @@ -284,6 +401,10 @@ var FormatButton = React.createClass({
});

module.exports = {
mounting_dialog_fields: mounting_dialog_fields,
mounting_dialog_options: mounting_dialog_options,
crypto_options_dialog_fields: crypto_options_dialog_fields,
crypto_options_dialog_options: crypto_options_dialog_options,
format_dialog: format_dialog,
FormatButton: FormatButton
};
27 changes: 3 additions & 24 deletions pkg/storaged/fsys-tab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,34 +118,13 @@ var FilesystemTab = React.createClass({

function mounting_dialog() {
dialog.open({ Title: _("Filesystem Mounting"),
Fields: [
{ SelectOne: "mounting",
Title: _("Mounting"),
Options: [
{ value: "default", Title: _("Default"), selected: !old_config },
{ value: "custom", Title: _("Custom"), selected: !!old_config }
],
},
{ TextInput: "mount_point",
Title: _("Mount Point"),
Value: old_dir,
visible: function (vals) {
return vals.mounting == "custom";
}
},
{ TextInput: "mount_options",
Title: _("Mount Options"),
Value: old_opts,
visible: function (vals) {
return vals.mounting == "custom";
}
}
],
Fields: FormatDialog.mounting_dialog_fields(!!old_config, old_dir, old_opts),
Action: {
Title: _("Apply"),
action: function (vals) {
return maybe_update_config(vals.mounting == "custom",
vals.mount_point, vals.mount_options);
vals.mount_point,
FormatDialog.mounting_dialog_options(vals));
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion test/verify/check-storage-hidden
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class TestStorage(StorageCase):
"passphrase2": "einszweidrei",
"mounting": "custom",
"mount_point": mount_point_1,
"crypto_options": "my-crypto-tag" })
"crypto_extra_options": CheckBoxText("my-crypto-tag") })
self.content_row_wait_in_col(2, 1, "46 MiB ext4 File System")
self.wait_in_storaged_configuration(mount_point_1)
self.wait_in_storaged_configuration("my-crypto-tag")
Expand Down
6 changes: 3 additions & 3 deletions test/verify/check-storage-luks
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class TestStorage(StorageCase):
"store_passphrase": True,
"mounting": "custom",
"mount_point": mount_point_secret,
"crypto_options": "crypto,options" })
"crypto_extra_options": CheckBoxText("crypto,options") })
self.content_row_wait_in_col(1, 1, "Encrypted data")
self.content_row_wait_in_col(2, 1, "ext4 File System")

Expand All @@ -76,8 +76,8 @@ class TestStorage(StorageCase):
# Change options. We keep trying until the stack has synched
# up with crypttab and we see the old options.
self.dialog_with_retry(trigger = lambda: self.content_tab_info_action(1, 2, "Options"),
expect = { "options": "crypto,options" },
values = { "options": "weird,options" })
expect = { "crypto_extra_options": CheckBoxText("crypto,options") },
values = { "crypto_extra_options": CheckBoxText("weird,options") })

assert m.execute("grep 'weird,options' /etc/crypttab") != ""
self.wait_in_storaged_configuration("weird,options")
Expand Down
58 changes: 58 additions & 0 deletions test/verify/check-storage-mounting
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,63 @@ class TestStorage(StorageCase):
self.dialog({ "type": "empty" })
self.content_row_wait_in_col(1, 1, "Unrecognized Data")

def testMountOptions(self):
m = self.machine
b = self.browser

if self.storaged_is_old_udisks:
self.skipTest("No mount/crypto options with old UDisks")

self.login_and_go("/storage")

# Add a disk
m.add_disk("50M", serial="MYDISK")
b.wait_in_text("#drives", "MYDISK")
b.click('#drives tr:contains("MYDISK")')
b.wait_visible('#storage-detail')

# Open format dialog and play with the checkboxes

self.content_tab_action(1, 1, "Format")
self.dialog_wait_open()
self.dialog_set_val("type", "luks+ext4")
self.dialog_set_val("mounting", "custom")

def wait_checked(field):
b.wait_present(self.dialog_field(field) + ":checked")

def wait_not_checked(field):
b.wait_present(self.dialog_field(field) + ":not(:checked)")

wait_checked("crypto_options_auto")
wait_checked("mount_auto")
wait_not_checked("crypto_options_ro")
wait_not_checked("mount_ro")

# Uncheck crypto auto. This gets propagated to mount auto.
self.dialog_set_val("crypto_options_auto", False)
wait_not_checked("mount_auto")

# Check crypto ro. This gets propagated to mount ro.
self.dialog_set_val("crypto_options_ro", True)
wait_checked("mount_ro")

# Set extra options.
self.dialog_set_val("crypto_extra_options", CheckBoxText("foo"))
self.dialog_set_val("mount_extra_options", CheckBoxText("foo"))

# Fill in the erst and do the format
self.dialog_set_val("passphrase", "vainu-reku-toma-rolle-kaja")
self.dialog_set_val("passphrase2", "vainu-reku-toma-rolle-kaja")
self.dialog_set_val("mount_point", "/data")
self.dialog_apply()
self.dialog_wait_close()

self.content_row_wait_in_col(1, 1, "Encrypted data")
self.content_row_wait_in_col(2, 1, "ext4 File System")
self.wait_in_storaged_configuration("/data")
m.execute("grep 'noauto,readonly,foo' /etc/crypttab")
m.execute("grep 'noauto,ro,foo' /etc/fstab")

if __name__ == '__main__':
test_main()
2 changes: 1 addition & 1 deletion test/verify/check-storage-msdos
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class TestStorage(StorageCase):
self.dialog_wait_not_visible("name")
self.dialog_wait_not_visible("mounting")
self.dialog_wait_not_visible("mount_point")
self.dialog_wait_not_visible("mount_options")
self.dialog_wait_not_visible("mount_auto")
self.dialog_apply()
self.dialog_wait_close()
self.content_row_wait_in_col(2, 1, "Extended Partition")
Expand Down

0 comments on commit 3729f86

Please sign in to comment.