aboutsummaryrefslogtreecommitdiff
path: root/hbak_common/src/config.rs
blob: 91a71ff350d56bc43aa4f896810f0c4f1ebeb095 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// hbak_common is the main hbak library implementing the protocol shared logic.
// Copyright (C) 2024  Himbeer <himbeerserverde@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use crate::proto::Volume;
use crate::LocalNodeError;

use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::net::SocketAddr;
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};

use serde::{Deserialize, Serialize};

/// A `NodeConfig` contains metadata about a node
/// such as its name or the nodes it replicates to or stores
/// as well as authentication and encryption secrets.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct NodeConfig {
    /// The device file the local btrfs file system is located at.
    pub device: String,
    /// The network address `hbakd` binds to. The default is `[::]:20406` (dual stack).
    pub bind_addr: Option<SocketAddr>,
    /// The name of the [`crate::proto::Node`].
    pub node_name: String,
    /// The subvolumes owned by the [`crate::proto::Node`], i.e. the subvolumes
    /// that originate from it.
    pub subvols: Vec<String>,
    /// The encryption passphrase for the subvolumes owned by this node.
    /// The backups can only be decrypted using this passphrase.
    ///
    /// **DO NOT reuse this passphrase across nodes as this undermines
    /// the end-to-end aspect of the encryption.**
    ///
    /// **Remember this passphrase at all costs. Losing it makes it impossible
    /// to recover any of the backups.**
    pub passphrase: String,
    /// The remote nodes to interact with by pushing to or pulling from them.
    pub remotes: Vec<RemoteNode>,
    /// The authentication details and privileges of other nodes
    /// for verification when they connect.
    pub auth: Vec<RemoteNodeAuth>,
}

impl NodeConfig {
    pub const PATH: &'static str = "/etc/hbak.conf";

    /// Loads the configuration file of the current machine.
    pub fn load() -> Result<Self, LocalNodeError> {
        let mut f = File::open(Self::PATH)?;

        if f.metadata()?.permissions().mode() & 0o7077 > 0 {
            return Err(LocalNodeError::InsecurePerms);
        }

        let mut s = String::new();
        f.read_to_string(&mut s)?;

        Ok(toml::from_str(&s)?)
    }

    /// Saves the configuration to the configuration file on the current machine.
    pub fn save(&self) -> Result<(), LocalNodeError> {
        let s = toml::to_string_pretty(self)?;

        let mut f = OpenOptions::new()
            .create(true)
            .read(false)
            .write(true)
            .append(false)
            .truncate(true)
            .mode(0o0600)
            .open(Self::PATH)?;

        write!(f, "{}", s)?;
        Ok(())
    }
}

/// A `RemoteNode` defines a network node that can be interacted with.
/// Backups can be pushed to or pulled from a `RemoteNode`.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct RemoteNode {
    /// The network address and port of the node to push to.
    pub address: String,
    /// The volumes to push to the remote node.
    pub push: Vec<Volume>,
    /// The volumes to pull from the remote node,
    /// must not include subvolumes owned by the local node.
    pub pull: Vec<Volume>,
}

/// A `RemoteNodeAuth` defines authentication and authorization details
/// of a network node.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct RemoteNodeAuth {
    /// The name of the remote node to apply the details to.
    pub node_name: String,
    /// A random value used by the remote node to compute the HMAC shared secret.
    pub verifier: Vec<u8>,
    /// The HMAC hash of verifier and passphrase for mutual authentication.
    pub key: Vec<u8>,
    /// The volumes the remote node is allowed to push.
    /// Must not include subvolumes owned by the local node.
    pub push: Vec<Volume>,
    /// The volumes the remote node is allowed to pull.
    pub pull: Vec<Volume>,
}