Skip to content

Commit 4e1b8d8

Browse files
committed
feat!: Add masterkey as credential option
1 parent 54463a9 commit 4e1b8d8

File tree

25 files changed

+467
-361
lines changed

25 files changed

+467
-361
lines changed

crates/core/src/commands/init.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::{
1313
error::RusticResult,
1414
id::Id,
1515
repofile::{ConfigFile, KeyId, configfile::RepositoryId},
16-
repository::Repository,
16+
repository::{Repository, credentials::Credentials},
1717
};
1818

1919
/// Initialize a new repository.
@@ -26,7 +26,7 @@ use crate::{
2626
/// # Arguments
2727
///
2828
/// * `repo` - The repository to initialize.
29-
/// * `pass` - The password to encrypt the key with.
29+
/// * `credentials` - The credentials to use.
3030
/// * `key_opts` - The options to create the key with.
3131
/// * `config_opts` - The options to create the config with.
3232
///
@@ -39,22 +39,22 @@ use crate::{
3939
/// A tuple of the key and the config file.
4040
pub(crate) fn init<P, S>(
4141
repo: &Repository<P, S>,
42-
pass: &str,
42+
credentials: &Credentials,
4343
key_opts: &KeyOptions,
4444
config_opts: &ConfigOptions,
45-
) -> RusticResult<(Key, KeyId, ConfigFile)> {
45+
) -> RusticResult<(Key, Option<KeyId>, ConfigFile)> {
4646
// Create config first to allow catching errors from here without writing anything
4747
let repo_id = RepositoryId::from(Id::random());
4848
let chunker_poly = random_poly()?;
4949
let mut config = ConfigFile::new(2, repo_id, chunker_poly);
5050
if repo.be_hot.is_some() {
51-
// for hot/cold repository, `config` must be identical to thee config file which is read by the backend, i.e. the one saved in the hot repo.
51+
// for hot/cold repository, `config` must be identical to the config file which is read by the backend, i.e. the one saved in the hot repo.
5252
// Note: init_with_config does handle the is_hot config correctly for the hot and the cold repo.
5353
config.is_hot = Some(true);
5454
}
5555
config_opts.apply(&mut config)?;
5656

57-
let (key, key_id) = init_with_config(repo, pass, key_opts, &config)?;
57+
let (key, key_id) = init_with_config(repo, credentials, key_opts, &config)?;
5858
info!("repository {repo_id} successfully created.");
5959

6060
Ok((key, key_id, config))
@@ -79,13 +79,19 @@ pub(crate) fn init<P, S>(
7979
/// The key used to encrypt the config.
8080
pub(crate) fn init_with_config<P, S>(
8181
repo: &Repository<P, S>,
82-
pass: &str,
82+
credentials: &Credentials,
8383
key_opts: &KeyOptions,
8484
config: &ConfigFile,
85-
) -> RusticResult<(Key, KeyId)> {
85+
) -> RusticResult<(Key, Option<KeyId>)> {
8686
repo.be.create()?;
87-
let (key, id) = init_key(repo, key_opts, pass)?;
88-
info!("key {id} successfully added.");
87+
let (key, id) = match credentials {
88+
Credentials::Password(password) => {
89+
let (key, id) = init_key(repo, key_opts, password)?;
90+
info!("key {id} successfully added.");
91+
(key, Some(id))
92+
}
93+
Credentials::Masterkey(key) => (key.key(), None),
94+
};
8995
save_config(repo, config.clone(), key)?;
9096

9197
Ok((key, id))

crates/core/src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ pub enum ErrorKind {
132132
/// general operations
133133
#[default]
134134
Other,
135-
/// password handling
136-
Password,
135+
/// credentials handling
136+
Credentials,
137137
/// the repository
138138
Repository,
139139
/// unsupported operations

crates/core/src/lib.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,16 @@ implement [`serde::Serialize`] and [`serde::Deserialize`].
2525
2626
```rust
2727
use rustic_backend::BackendOptions;
28-
use rustic_core::{BackupOptions, ConfigOptions, KeyOptions, PathList,
29-
Repository, RepositoryOptions, SnapshotOptions
28+
use rustic_core::{repofile::MasterKey, BackupOptions, ConfigOptions, Credentials,
29+
KeyOptions, PathList, Repository, RepositoryOptions, SnapshotOptions,
3030
};
3131
3232
// Initialize the repository in a temporary dir
3333
let repo_dir = tempfile::tempdir().unwrap();
3434
35-
let repo_opts = RepositoryOptions::default()
36-
.password("test");
35+
let repo_opts = RepositoryOptions::default();
36+
// In real life, make sure to save this credential!
37+
let credentials = Credentials::Masterkey(MasterKey::new());
3738
3839
// Initialize Backends
3940
let backends = BackendOptions::default()
@@ -45,10 +46,13 @@ implement [`serde::Serialize`] and [`serde::Deserialize`].
4546
4647
let config_opts = ConfigOptions::default();
4748
48-
let _repo = Repository::new(&repo_opts, &backends.clone()).unwrap().init(&key_opts, &config_opts).unwrap();
49+
let _repo = Repository::new(&repo_opts, &backends)
50+
.unwrap()
51+
.init(&credentials, &key_opts, &config_opts)
52+
.unwrap();
4953
5054
// We could have used _repo directly, but open the repository again to show how to open it...
51-
let repo = Repository::new(&repo_opts, &backends).unwrap().open().unwrap();
55+
let repo = Repository::new(&repo_opts, &backends).unwrap().open(&credentials).unwrap();
5256
5357
// Get all snapshots from the repository
5458
let snaps = repo.get_all_snapshots().unwrap();
@@ -165,5 +169,6 @@ pub use crate::{
165169
FullIndex, IdIndex, IndexedFull, IndexedIds, IndexedStatus, IndexedTree, Open, OpenStatus,
166170
Repository, RepositoryOptions,
167171
command_input::{CommandInput, CommandInputErrorKind},
172+
credentials::{CredentialOptions, Credentials},
168173
},
169174
};

crates/core/src/repofile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ pub use {
160160
},
161161
configfile::{Chunker, ConfigFile},
162162
indexfile::{IndexBlob, IndexFile, IndexId, IndexPack},
163-
keyfile::{KeyFile, KeyId},
163+
keyfile::{KeyFile, KeyId, MasterKey},
164164
packfile::{HeaderEntry, PackHeader, PackHeaderLength, PackHeaderRef, PackId},
165165
snapshotfile::{
166166
DeleteOption, PathList, SnapshotFile, SnapshotId, SnapshotModification, SnapshotSummary,

crates/core/src/repofile/keyfile.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -306,31 +306,43 @@ fn log_2(x: u32) -> KeyFileResult<u8> {
306306
///
307307
/// This is used to verify the integrity of the key
308308
#[serde_as]
309-
#[derive(Serialize, Deserialize, Debug)]
310-
pub(crate) struct Mac {
309+
#[derive(Serialize, Deserialize, Debug, Clone)]
310+
pub struct Mac {
311311
/// The key used for the mac
312312
#[serde_as(as = "Base64")]
313-
k: Vec<u8>,
313+
pub k: Vec<u8>,
314314

315315
/// The random value used for the mac
316316
#[serde_as(as = "Base64")]
317-
r: Vec<u8>,
317+
pub r: Vec<u8>,
318318
}
319319

320320
/// The master key of a [`Key`]
321321
///
322322
/// This is used to encrypt the key
323323
#[serde_as]
324-
#[derive(Serialize, Deserialize, Debug)]
325-
pub(crate) struct MasterKey {
324+
#[derive(Serialize, Deserialize, Debug, Clone)]
325+
pub struct MasterKey {
326326
/// The mac of the key
327-
mac: Mac,
327+
pub mac: Mac,
328328
/// The encrypted key
329329
#[serde_as(as = "Base64")]
330-
encrypt: Vec<u8>,
330+
pub encrypt: Vec<u8>,
331+
}
332+
333+
impl Default for MasterKey {
334+
fn default() -> Self {
335+
Self::from_key(Key::new())
336+
}
331337
}
332338

333339
impl MasterKey {
340+
/// Create a random [`MasterKey`]
341+
#[must_use]
342+
pub fn new() -> Self {
343+
Self::default()
344+
}
345+
334346
/// Create a [`MasterKey`] from a [`Key`]
335347
///
336348
/// # Arguments
@@ -340,7 +352,7 @@ impl MasterKey {
340352
/// # Returns
341353
///
342354
/// The created [`MasterKey`]
343-
fn from_key(key: Key) -> Self {
355+
pub(crate) fn from_key(key: Key) -> Self {
344356
let (encrypt, k, r) = key.to_keys();
345357
Self {
346358
encrypt,
@@ -349,7 +361,7 @@ impl MasterKey {
349361
}
350362

351363
/// Get the [`Key`] from the [`MasterKey`]
352-
fn key(&self) -> Key {
364+
pub(crate) fn key(&self) -> Key {
353365
Key::from_keys(&self.encrypt, &self.mac.k, &self.mac.r)
354366
}
355367
}
@@ -407,7 +419,7 @@ pub(crate) fn find_key_in_backend<B: ReadBackend>(
407419
}
408420

409421
Err(RusticError::new(
410-
ErrorKind::Password,
422+
ErrorKind::Credentials,
411423
"The password that has been entered, seems to be incorrect. No suitable key found for the given password. Please check your password and try again.",
412424
).attach_error_code("C002"))
413425
}

0 commit comments

Comments
 (0)