ant_node/
utils.rs

1// Copyright 2025 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use ant_protocol::node::get_antnode_root_dir;
10use eyre::eyre;
11use libp2p::identity::Keypair;
12use std::io::Write;
13use std::path::{Path, PathBuf};
14
15/// The keypair is located inside the root directory. At the same time, when no dir is specified,
16/// the dir name is derived from the keypair used in the application: the peer ID is used as the directory name.
17pub fn get_root_dir_and_keypair(root_dir: &Option<PathBuf>) -> eyre::Result<(PathBuf, Keypair)> {
18    match root_dir {
19        Some(dir) => {
20            std::fs::create_dir_all(dir)?;
21
22            let secret_key_path = dir.join("secret-key");
23            Ok((dir.clone(), keypair_from_path(secret_key_path)?))
24        }
25        None => {
26            let secret_key = libp2p::identity::ed25519::SecretKey::generate();
27            let keypair: Keypair =
28                libp2p::identity::ed25519::Keypair::from(secret_key.clone()).into();
29            let peer_id = keypair.public().to_peer_id();
30
31            let dir = get_antnode_root_dir(peer_id)?;
32            std::fs::create_dir_all(&dir)?;
33
34            let secret_key_path = dir.join("secret-key");
35
36            let mut file = create_secret_key_file(secret_key_path)
37                .map_err(|err| eyre!("could not create secret key file: {err}"))?;
38            file.write_all(secret_key.as_ref())?;
39
40            Ok((dir, keypair))
41        }
42    }
43}
44
45fn keypair_from_path(path: impl AsRef<Path>) -> eyre::Result<Keypair> {
46    let keypair = match std::fs::read(&path) {
47        // If the file is opened successfully, read the key from it
48        Ok(key) => {
49            let keypair = Keypair::ed25519_from_bytes(key)
50                .map_err(|err| eyre!("could not read ed25519 key from file: {err}"))?;
51
52            info!("loaded secret key from file: {:?}", path.as_ref());
53
54            keypair
55        }
56        // In case the file is not found, generate a new keypair and write it to the file
57        Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
58            let secret_key = libp2p::identity::ed25519::SecretKey::generate();
59            let mut file = create_secret_key_file(&path)
60                .map_err(|err| eyre!("could not create secret key file: {err}"))?;
61            file.write_all(secret_key.as_ref())?;
62
63            info!("generated new key and stored to file: {:?}", path.as_ref());
64
65            libp2p::identity::ed25519::Keypair::from(secret_key).into()
66        }
67        // Else the file can't be opened, for whatever reason (e.g. permissions).
68        Err(err) => {
69            return Err(eyre!("failed to read secret key file: {err}"));
70        }
71    };
72
73    Ok(keypair)
74}
75
76fn create_secret_key_file(path: impl AsRef<Path>) -> eyre::Result<std::fs::File, std::io::Error> {
77    let mut opt = std::fs::OpenOptions::new();
78    let _ = opt.write(true).create_new(true);
79
80    // On Unix systems, make sure only the current user can read/write.
81    #[cfg(unix)]
82    {
83        use std::os::unix::fs::OpenOptionsExt;
84        let _ = opt.mode(0o600);
85    }
86
87    opt.open(path)
88}