diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index 2c8303a4c427..794dbfa9d3a1 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -21,7 +21,7 @@ import cockpit from "cockpit"; import client from "../client.js"; import { - edit_crypto_config, parse_options, unparse_options, extract_option, + parse_options, unparse_options, extract_option, get_parent_blocks, is_netdev, decode_filename, encode_filename, block_name, get_active_usage, reload_systemd, teardown_active_usage, @@ -42,6 +42,7 @@ import { import { get_fstab_config, is_valid_mount_point } from "../filesystem/utils.jsx"; import { init_existing_passphrase, unlock_with_type } from "../crypto/keyslots.jsx"; +import { edit_crypto_config } from "../crypto/utils.jsx"; import { job_progress_wrapper } from "../jobs-panel.jsx"; import { at_boot_input, mount_options } from "../filesystem/mounting-dialog.jsx"; import { remember_passphrase } from "../anaconda.jsx"; diff --git a/pkg/storaged/crypto/encryption.jsx b/pkg/storaged/crypto/encryption.jsx index 4245de38131d..75f9e9a9c739 100644 --- a/pkg/storaged/crypto/encryption.jsx +++ b/pkg/storaged/crypto/encryption.jsx @@ -28,12 +28,13 @@ import * as python from "python.js"; import * as timeformat from "timeformat.js"; import { dialog_open, TextInput, PassInput } from "../dialog.jsx"; -import { block_name, encode_filename, decode_filename, parse_options, unparse_options, extract_option, edit_crypto_config } from "../utils.js"; +import { block_name, encode_filename, decode_filename, parse_options, unparse_options, extract_option } from "../utils.js"; import { StorageCard, StorageDescription, new_card } from "../pages.jsx"; import luksmeta_monitor_hack_py from "./luksmeta-monitor-hack.py"; import { is_mounted } from "../filesystem/utils.jsx"; import { StorageLink } from "../storage-controls.jsx"; import { CryptoKeyslots } from "./keyslots.jsx"; +import { edit_crypto_config } from "./utils.jsx"; const _ = cockpit.gettext; diff --git a/pkg/storaged/crypto/keyslots.jsx b/pkg/storaged/crypto/keyslots.jsx index 9a6962d6fbe9..431716e7f27e 100644 --- a/pkg/storaged/crypto/keyslots.jsx +++ b/pkg/storaged/crypto/keyslots.jsx @@ -38,11 +38,12 @@ import { dialog_open, SelectOneRadio, TextInput, PassInput, Skip } from "../dialog.jsx"; -import { decode_filename, encode_filename, get_block_mntopts, block_name, for_each_async, get_children, parse_options, unparse_options, edit_crypto_config } from "../utils.js"; +import { decode_filename, encode_filename, get_block_mntopts, block_name, for_each_async, get_children, parse_options, unparse_options } from "../utils.js"; import { StorageButton } from "../storage-controls.jsx"; import clevis_luks_passphrase_sh from "./clevis-luks-passphrase.sh"; import { validate_url, get_tang_adv, TangKeyVerification } from "./tang.jsx"; +import { edit_crypto_config } from "./utils.jsx"; const _ = cockpit.gettext; diff --git a/pkg/storaged/crypto/utils.jsx b/pkg/storaged/crypto/utils.jsx new file mode 100644 index 000000000000..9c216d1a63ac --- /dev/null +++ b/pkg/storaged/crypto/utils.jsx @@ -0,0 +1,79 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2024 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + +import { encode_filename, decode_filename, parse_options, extract_option, unparse_options } from "../utils.js"; + +export function edit_crypto_config(block, modify) { + let old_config, new_config; + + function commit() { + new_config[1]["track-parents"] = { t: 'b', v: true }; + if (old_config) + return block.UpdateConfigurationItem(old_config, new_config, { }); + else + return block.AddConfigurationItem(new_config, { }); + } + + return block.GetSecretConfiguration({}).then( + function (items) { + old_config = items.find(c => c[0] == "crypttab"); + new_config = ["crypttab", old_config ? Object.assign({ }, old_config[1]) : { }]; + + // UDisks insists on always having a "passphrase-contents" field when + // adding a crypttab entry, but doesn't include one itself when returning + // an entry without a stored passphrase. + // + if (!new_config[1]['passphrase-contents']) + new_config[1]['passphrase-contents'] = { t: 'ay', v: encode_filename("") }; + + return modify(new_config[1], commit); + }); +} + +export function set_crypto_options(block, readonly, auto, nofail, netdev) { + return edit_crypto_config(block, (config, commit) => { + const opts = config.options ? parse_options(decode_filename(config.options.v)) : []; + if (readonly !== null) { + extract_option(opts, "readonly"); + if (readonly) + opts.push("readonly"); + } + if (auto !== null) { + extract_option(opts, "noauto"); + if (!auto) + opts.push("noauto"); + } + if (nofail !== null) { + extract_option(opts, "nofail"); + if (nofail) + opts.push("nofail"); + } + if (netdev !== null) { + extract_option(opts, "_netdev"); + if (netdev) + opts.push("_netdev"); + } + config.options = { t: 'ay', v: encode_filename(unparse_options(opts)) }; + return commit(); + }); +} + +export function set_crypto_auto_option(block, flag) { + return set_crypto_options(block, null, flag, null, null); +} diff --git a/pkg/storaged/filesystem/mounting-dialog.jsx b/pkg/storaged/filesystem/mounting-dialog.jsx index f70e8a8fa866..8236db0da867 100644 --- a/pkg/storaged/filesystem/mounting-dialog.jsx +++ b/pkg/storaged/filesystem/mounting-dialog.jsx @@ -23,7 +23,7 @@ import client from "../client.js"; import { encode_filename, parse_options, unparse_options, extract_option, reload_systemd, - set_crypto_options, is_mounted_synch, + is_mounted_synch, get_active_usage, teardown_active_usage, } from "../utils.js"; @@ -35,6 +35,7 @@ import { } from "../dialog.jsx"; import { init_existing_passphrase, unlock_with_type } from "../crypto/keyslots.jsx"; import { initial_tab_options, mount_explanation } from "../block/format-dialog.jsx"; +import { set_crypto_options } from "../crypto/utils.jsx"; import { is_mounted, get_fstab_config, diff --git a/pkg/storaged/utils.js b/pkg/storaged/utils.js index b57925b2297b..5c303c401ce4 100644 --- a/pkg/storaged/utils.js +++ b/pkg/storaged/utils.js @@ -70,65 +70,6 @@ export function extract_option(split, opt) { } } -export function edit_crypto_config(block, modify) { - let old_config, new_config; - - function commit() { - new_config[1]["track-parents"] = { t: 'b', v: true }; - if (old_config) - return block.UpdateConfigurationItem(old_config, new_config, { }); - else - return block.AddConfigurationItem(new_config, { }); - } - - return block.GetSecretConfiguration({}).then( - function (items) { - old_config = items.find(c => c[0] == "crypttab"); - new_config = ["crypttab", old_config ? Object.assign({ }, old_config[1]) : { }]; - - // UDisks insists on always having a "passphrase-contents" field when - // adding a crypttab entry, but doesn't include one itself when returning - // an entry without a stored passphrase. - // - if (!new_config[1]['passphrase-contents']) - new_config[1]['passphrase-contents'] = { t: 'ay', v: encode_filename("") }; - - return modify(new_config[1], commit); - }); -} - -export function set_crypto_options(block, readonly, auto, nofail, netdev) { - return edit_crypto_config(block, (config, commit) => { - const opts = config.options ? parse_options(decode_filename(config.options.v)) : []; - if (readonly !== null) { - extract_option(opts, "readonly"); - if (readonly) - opts.push("readonly"); - } - if (auto !== null) { - extract_option(opts, "noauto"); - if (!auto) - opts.push("noauto"); - } - if (nofail !== null) { - extract_option(opts, "nofail"); - if (nofail) - opts.push("nofail"); - } - if (netdev !== null) { - extract_option(opts, "_netdev"); - if (netdev) - opts.push("_netdev"); - } - config.options = { t: 'ay', v: encode_filename(unparse_options(opts)) }; - return commit(); - }); -} - -export function set_crypto_auto_option(block, flag) { - return set_crypto_options(block, null, flag, null, null); -} - export let hostnamed = cockpit.dbus("org.freedesktop.hostname1").proxy(); // for unit tests