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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Port of `request/fetch.go` from upstream `browserpass-native`.
#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
#![allow(unused_assignments)] // Go declares `var gpgPath string` then assigns;
// the empty-string init is unused but kept for
// port fidelity per PORT.md Rule E.
use crate::ported::errors;
use crate::ported::helpers;
use crate::ported::request::common::normalizePasswordStorePath;
use crate::ported::request::process::request;
use crate::ported::response;
/// Port of `fetchDecryptedContents()` from `request/fetch.go:13`.
pub fn fetchDecryptedContents(request: &request) {
let mut responseData = response::MakeFetchResponse(); // go:14
if !request.File.ends_with(".gpg") { // go:16 strings.HasSuffix(request.File, ".gpg")
eprintln!(
"The requested password file '{}' does not have the expected '.gpg' extension",
request.File
);
response::SendErrorAndExit( // go:18-25
errors::Code::InvalidPasswordFileExtension,
Some(response::params_of(&[
(errors::field::MESSAGE, "The requested password file does not have the expected '.gpg' extension"),
(errors::field::ACTION, "fetch"),
(errors::field::FILE, &request.File),
])),
);
}
let store = match request.Settings.Stores.get(&request.StoreID) { // go:28
Some(s) => s.clone(),
None => { // go:29-41
eprintln!(
"The password store with ID '{}' is not present in the list of stores '{:?}'",
request.StoreID, request.Settings.Stores
);
response::SendErrorAndExit( // go:34-41
errors::Code::InvalidPasswordStore,
Some(response::params_of(&[
(errors::field::MESSAGE, "The password store is not present in the list of stores"),
(errors::field::ACTION, "fetch"),
(errors::field::STORE_ID, &request.StoreID),
])),
);
}
};
let normalizedStorePath = match normalizePasswordStorePath(&store.Path) { // go:44
Ok(p) => p,
Err(e) => { // go:45-59
eprintln!(
"The password store '{:?}' is not accessible at its location: {}",
store, e
);
response::SendErrorAndExit( // go:50-59
errors::Code::InaccessiblePasswordStore,
Some(response::params_of(&[
(errors::field::MESSAGE, "The password store is not accessible"),
(errors::field::ACTION, "fetch"),
(errors::field::ERROR, &e),
(errors::field::STORE_ID, &store.ID),
(errors::field::STORE_NAME, &store.Name),
(errors::field::STORE_PATH, &store.Path),
])),
);
}
};
let mut store = store; // go:62 (was immutable above)
store.Path = normalizedStorePath.to_string_lossy().into_owned(); // go:62
let mut gpgPath: String = String::new(); // go:64 var gpgPath string
if !request.Settings.GpgPath.is_empty() || !store.Settings.GpgPath.is_empty() { // go:65
if !request.Settings.GpgPath.is_empty() { // go:66
gpgPath = request.Settings.GpgPath.clone(); // go:67
} else { // go:68
gpgPath = store.Settings.GpgPath.clone(); // go:69
}
if let Err(e) = helpers::ValidateGpgBinary(&gpgPath) { // go:71
eprintln!("The provided gpg binary path '{gpgPath}' is invalid: {e}"); // go:72-75
response::SendErrorAndExit( // go:76-84
errors::Code::InvalidGpgPath,
Some(response::params_of(&[
(errors::field::MESSAGE, "The provided gpg binary path is invalid"),
(errors::field::ACTION, "fetch"),
(errors::field::ERROR, &e),
(errors::field::GPG_PATH, &gpgPath),
])),
);
}
} else { // go:87
match helpers::DetectGpgBinary() { // go:88
Ok(p) => gpgPath = p,
Err(e) => { // go:89-97
eprintln!("Unable to detect the location of the gpg binary: {e}"); // go:90
response::SendErrorAndExit( // go:91-97
errors::Code::UnableToDetectGpgPath,
Some(response::params_of(&[
(errors::field::MESSAGE, "Unable to detect the location of the gpg binary"),
(errors::field::ACTION, "fetch"),
(errors::field::ERROR, &e),
])),
);
}
}
}
let file_path = normalizedStorePath.join(&request.File); // go:101 filepath.Join(store.Path, request.File)
match helpers::GpgDecryptFile(&file_path, &gpgPath) { // go:101
Ok(contents) => { // go:102
responseData.Contents = contents;
}
Err(e) => { // go:102-117
eprintln!(
"Unable to decrypt the password file '{}' in the password store '{:?}': {}",
request.File, store, e
);
response::SendErrorAndExit( // go:107-117
errors::Code::UnableToDecryptPasswordFile,
Some(response::params_of(&[
(errors::field::MESSAGE, "Unable to decrypt the password file"),
(errors::field::ACTION, "fetch"),
(errors::field::ERROR, &e),
(errors::field::FILE, &request.File),
(errors::field::STORE_ID, &store.ID),
(errors::field::STORE_NAME, &store.Name),
(errors::field::STORE_PATH, &store.Path),
])),
);
}
}
response::SendOk(responseData); // go:121
}
#[allow(non_snake_case)]
const _: () = ();