Skip to content

Commit b2aa836

Browse files
Trolldemortedfsck
authored andcommitted
Fix insert xss, add admins to users
1 parent 9017715 commit b2aa836

File tree

3 files changed

+165
-89
lines changed

3 files changed

+165
-89
lines changed

src/main.rs

+81-34
Original file line numberDiff line numberDiff line change
@@ -125,65 +125,77 @@ struct DeployInput {
125125
}
126126

127127
#[post("/", data = "<form>")]
128-
fn index_post(form: Result<Form<FormInput>, FormError>) -> content::Html<String> {
129-
content::Html(match form {
128+
fn index_post(form: Result<Form<FormInput>, FormError>) -> Template {
129+
match form {
130130
Ok(form) => {
131131
let config = &*CONFIG.lock().unwrap();
132132
let admin = if form.authkey == config.admin_psk {
133133
true
134134
} else if &form.authkey == &config.user_psk {
135135
false
136136
} else {
137-
return content::Html(format!("Wrong AUTHKEY: {:?}", form));
137+
return Template::render("insert_result", &format!("Wrong authkey: {:?}", form));
138138
};
139139
println!("authkey {} admin={}", &form.authkey, admin);
140140
if form.radio == FormOption::GitHub {
141141
match storage::handle_submission("github", &form.github_username, &form.name, admin)
142142
{
143-
Ok(_) => format!(
144-
"<b>SUCCESS added github user {:?}</b>",
145-
&form.github_username
143+
Ok(_) => Template::render(
144+
"insert_result",
145+
&format!("Successfully added github user {:?}", &form.github_username),
146146
),
147-
Err(e) => format!("ERROR: {:?}", e),
147+
Err(e) => Template::render("insert_result", &format!("ERROR: {:?}", e)),
148148
}
149149
} else if form.radio == FormOption::TubLab {
150150
match storage::handle_submission("tublab", &form.tublab_username, &form.name, admin)
151151
{
152-
Ok(_) => format!(
153-
"<b>SUCCESS added tubit gitlab user {:?}</b>",
154-
&form.tublab_username
152+
Ok(_) => Template::render(
153+
"insert_result",
154+
&format!(
155+
"Successfully added tubit gitlab user {:?}",
156+
&form.tublab_username
157+
),
155158
),
156-
Err(e) => format!("ERROR: {:?}", e),
159+
Err(e) => Template::render("insert_result", &format!("ERROR: {:?}", e)),
157160
}
158161
} else if form.radio == FormOption::GitLab {
159162
match storage::handle_submission("gitlab", &form.gitlab_username, &form.name, admin)
160163
{
161-
Ok(_) => format!(
162-
"<b>SUCCESS added gitlab.com user {:?}</b>",
163-
&form.gitlab_username
164+
Ok(_) => Template::render(
165+
"insert_result",
166+
&format!(
167+
"Successfully added gitlab.com user {:?}",
168+
&form.gitlab_username
169+
),
164170
),
165-
Err(e) => format!("ERROR: {:?}", e),
171+
Err(e) => Template::render("insert_result", &format!("ERROR: {:?}", e)),
166172
}
167173
} else if form.radio == FormOption::EnoLab {
168174
match storage::handle_submission("enolab", &form.enolab_username, &form.name, admin)
169175
{
170-
Ok(_) => format!(
171-
"<b>SUCCESS added enoflag gitlab user {:?}</b>",
172-
&form.enolab_username
176+
Ok(_) => Template::render(
177+
"insert_result",
178+
&format!(
179+
"Successfully added enoflag gitlab user {:?}",
180+
&form.enolab_username
181+
),
173182
),
174-
Err(e) => format!("ERROR: {:?}", e),
183+
Err(e) => Template::render("insert_result", &format!("ERROR: {:?}", e)),
175184
}
176185
} else if form.radio == FormOption::PubKey {
177186
match storage::handle_raw_submission(&form.name, &form.pub_key, admin) {
178-
Ok(_) => format!("<b>SUCCESS added raw pubkey {:?}</b>", &form.pub_key),
179-
Err(e) => format!("ERROR: {:?}", e),
187+
Ok(_) => Template::render(
188+
"insert_result",
189+
&format!("Successfully added raw pubkey{:?}", &form.pub_key),
190+
),
191+
Err(e) => Template::render("insert_result", &format!("ERROR: {:?}", e)),
180192
}
181193
} else {
182-
format!("ERROR: {:?}", form)
194+
Template::render("insert_result", &format!("ERROR: {:?}", form))
183195
}
184196
}
185-
Err(e) => format!("Invalid form input: {:?}", e),
186-
})
197+
Err(e) => Template::render("insert_result", &format!("Invalid form input: {:?}", e)),
198+
}
187199
}
188200

189201
#[get("/")]
@@ -246,10 +258,30 @@ fn main() {
246258
let program = args[0].clone();
247259
let mut opts = Options::new();
248260
opts.optflag("h", "help", "Print this help menu");
249-
opts.optopt("a", "admin-servers", "Set the destinations (remote server) for the admin group", "ADMIN_SERVERS");
250-
opts.optopt("p", "admin-psk", "Set the pre-shared key to add keys the admin group", "ADMIN_PSK");
251-
opts.optopt("u", "user-servers", "Set the destinations (remote server) for the user group", "USER_SERVERS");
252-
opts.optopt("q", "user-psk", "Set the pre-shared key to add keys the user group", "USER_PSK");
261+
opts.optopt(
262+
"a",
263+
"admin-servers",
264+
"Set the destinations (remote server) for the admin group",
265+
"ADMIN_SERVERS",
266+
);
267+
opts.optopt(
268+
"p",
269+
"admin-psk",
270+
"Set the pre-shared key to add keys the admin group",
271+
"ADMIN_PSK",
272+
);
273+
opts.optopt(
274+
"u",
275+
"user-servers",
276+
"Set the destinations (remote server) for the user group",
277+
"USER_SERVERS",
278+
);
279+
opts.optopt(
280+
"q",
281+
"user-psk",
282+
"Set the pre-shared key to add keys the user group",
283+
"USER_PSK",
284+
);
253285

254286
let matches = match opts.parse(&args[1..]) {
255287
Ok(m) => m,
@@ -270,15 +302,15 @@ fn main() {
270302
Some(admin) => parse_destinations(&admin),
271303
None => {
272304
println!("Warning: No admin servers set");
273-
Ok(vec!())
305+
Ok(vec![])
274306
}
275307
};
276308

277309
let user_env = match matches.opt_str("u") {
278310
Some(user) => parse_destinations(&user),
279311
None => {
280312
println!("Warning: No user servers set");
281-
Ok(vec!())
313+
Ok(vec![])
282314
}
283315
};
284316

@@ -301,13 +333,29 @@ fn main() {
301333
config
302334
.admin_destinations
303335
.extend(config.user_destinations.iter().cloned());
304-
305-
config.user_psk = matches.opt_str("q").unwrap_or_else(||{
336+
println!(
337+
"admin destinations: {:?}",
338+
&config
339+
.admin_destinations
340+
.iter()
341+
.map(|d| d.destination_name.clone())
342+
.collect::<String>()
343+
);
344+
println!(
345+
"user destinations: {:?}",
346+
&config
347+
.user_destinations
348+
.iter()
349+
.map(|d| d.destination_name.clone())
350+
.collect::<String>()
351+
);
352+
353+
config.user_psk = matches.opt_str("q").unwrap_or_else(|| {
306354
println!("Warning: User PSK not set.");
307355
"default".to_string()
308356
});
309357

310-
config.admin_psk = matches.opt_str("p").unwrap_or_else(||{
358+
config.admin_psk = matches.opt_str("p").unwrap_or_else(|| {
311359
println!("Warning: Admin PSK not set.");
312360
"default".to_string()
313361
});
@@ -338,7 +386,6 @@ fn parse_destinations(input: &str) -> Result<Vec<Destination>, EnokeysError> {
338386
return Ok(vec![]);
339387
}
340388
let entries: Vec<&str> = input.split(",").collect();
341-
println!("{:?}", &entries);
342389
let mut destinations = vec![];
343390
for entry in entries {
344391
let split: Vec<&str> = entry.split('@').collect();

src/storage.rs

+65-55
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,10 @@ pub fn handle_submission(
6565

6666
fn generate_authorized_key_file(
6767
authorized_keys_file_name: &PathBuf,
68-
providers_storage_file_name: &PathBuf,
69-
raw_storage_file_name: &PathBuf,
68+
providers_storage_file_names: &[&PathBuf],
69+
raw_storage_file_names: &[&PathBuf],
7070
) -> Result<(), EnokeysError> {
7171
let mut authorized_keys_file = File::create(&authorized_keys_file_name)?;
72-
let mut storage_file = OpenOptions::new()
73-
.read(true)
74-
.write(true)
75-
.create(true)
76-
.open(&providers_storage_file_name)?;
77-
let mut storage_file_content = String::new();
7872

7973
// append deploy key
8074
let mut deploy_key = String::new();
@@ -89,54 +83,19 @@ fn generate_authorized_key_file(
8983
}
9084

9185
// append raw keys
92-
let mut raw_keys = String::new();
93-
if let Ok(mut raw_keys_file) = File::open(&raw_storage_file_name) {
94-
raw_keys_file.read_to_string(&mut raw_keys)?;
95-
match PublicKey::parse(&raw_keys) {
96-
Ok(key) => match &key.comment {
97-
Some(ref comment) => {
98-
let comment = USERNAME_REGEX.replace_all(&comment, "_");
99-
let line = format!(
100-
"{} {} {}\n",
101-
key.keytype(),
102-
base64::encode(&key.data()),
103-
&comment[0..min(comment.len(), 100)]
104-
);
105-
write!(authorized_keys_file, "{}", &line)?
106-
}
107-
None => writeln!(
108-
authorized_keys_file,
109-
"{} {}",
110-
key.keytype(),
111-
base64::encode(&key.data())
112-
)?,
113-
},
114-
Err(e) => println!("Failed to parse PublicKey: {:?}", e),
115-
}
116-
}
117-
118-
// append keys from providers
119-
storage_file.read_to_string(&mut storage_file_content)?;
120-
for line in storage_file_content
121-
.split('\n')
122-
.filter(|&i| !i.is_empty())
123-
.filter(|&s| &s[0..1] != "#")
124-
{
125-
let entry = line.split(':').collect::<Vec<&str>>();
126-
let user_keys = scraper::fetch(entry[1], entry[0])?;
127-
for key in user_keys {
128-
println!("parsing key: {}", &key);
129-
match PublicKey::parse(&key) {
86+
for raw_storage_file_name in raw_storage_file_names {
87+
let mut raw_keys = String::new();
88+
if let Ok(mut raw_keys_file) = File::open(&raw_storage_file_name) {
89+
raw_keys_file.read_to_string(&mut raw_keys)?;
90+
match PublicKey::parse(&raw_keys) {
13091
Ok(key) => match &key.comment {
13192
Some(ref comment) => {
132-
let comment = USERNAME_REGEX.replace_all(&comment, " ");
93+
let comment = USERNAME_REGEX.replace_all(&comment, "_");
13394
let line = format!(
134-
"{} {} {}_({}@{})\n",
95+
"{} {} {}\n",
13596
key.keytype(),
13697
base64::encode(&key.data()),
137-
&comment[0..min(comment.len(), 100)],
138-
entry[1],
139-
entry[0]
98+
&comment[0..min(comment.len(), 100)]
14099
);
141100
write!(authorized_keys_file, "{}", &line)?
142101
}
@@ -151,19 +110,70 @@ fn generate_authorized_key_file(
151110
}
152111
}
153112
}
113+
114+
// append keys from providers
115+
for providers_storage_file_name in providers_storage_file_names {
116+
let mut storage_file = OpenOptions::new()
117+
.read(true)
118+
.write(true)
119+
.create(true)
120+
.open(&providers_storage_file_name)?;
121+
let mut storage_file_content = String::new();
122+
storage_file.read_to_string(&mut storage_file_content)?;
123+
for line in storage_file_content
124+
.split('\n')
125+
.filter(|&i| !i.is_empty())
126+
.filter(|&s| &s[0..1] != "#")
127+
{
128+
let entry = line.split(':').collect::<Vec<&str>>();
129+
let user_keys = scraper::fetch(entry[1], entry[0])?;
130+
for key in user_keys {
131+
println!("parsing key: {}", &key);
132+
match PublicKey::parse(&key) {
133+
Ok(key) => match &key.comment {
134+
Some(ref comment) => {
135+
let comment = USERNAME_REGEX.replace_all(&comment, " ");
136+
let line = format!(
137+
"{} {} {}_({}@{})\n",
138+
key.keytype(),
139+
base64::encode(&key.data()),
140+
&comment[0..min(comment.len(), 100)],
141+
entry[1],
142+
entry[0]
143+
);
144+
write!(authorized_keys_file, "{}", &line)?
145+
}
146+
None => writeln!(
147+
authorized_keys_file,
148+
"{} {}",
149+
key.keytype(),
150+
base64::encode(&key.data())
151+
)?,
152+
},
153+
Err(e) => println!("Failed to parse PublicKey: {:?}", e),
154+
}
155+
}
156+
}
157+
}
154158
Ok(())
155159
}
156160

157161
pub fn generate_authorized_key_files() -> Result<(), EnokeysError> {
158162
generate_authorized_key_file(
159163
&ADMIN_DESTINATIONS_AUTHORIZED_KEYS,
160-
&ADMIN_DESTINATIONS_STORAGE_PROVIDERS,
161-
&ADMIN_DESTINATIONS_STORAGE_RAW,
164+
&[&ADMIN_DESTINATIONS_STORAGE_PROVIDERS],
165+
&[&ADMIN_DESTINATIONS_STORAGE_RAW],
162166
)?;
163167
generate_authorized_key_file(
164168
&USER_DESTINATIONS_AUTHORIZED_KEYS,
165-
&USER_DESTINATIONS_STORAGE_PROVIDERS,
166-
&USER_DESTINATIONS_STORAGE_RAW,
169+
&[
170+
&ADMIN_DESTINATIONS_STORAGE_PROVIDERS,
171+
&USER_DESTINATIONS_STORAGE_PROVIDERS,
172+
],
173+
&[
174+
&ADMIN_DESTINATIONS_STORAGE_RAW,
175+
&USER_DESTINATIONS_STORAGE_RAW,
176+
],
167177
)?;
168178
Ok(())
169179
}

templates/insert_result.html.hbs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<title>ENOKEY - SSH PublicKey Self-Service Center</title>
5+
<!-- Required meta tags -->
6+
<meta charset="utf-8">
7+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
8+
9+
<!-- Bootstrap CSS -->
10+
<link rel="stylesheet" href="static/css/bootstrap.min.css">
11+
<link rel="stylesheet" href="static/css/style.css">
12+
</head>
13+
<body>
14+
<nav class="navbar navbar-expand-lg navbar-light bg-light">
15+
<a class="navbar-brand" href="/">ENOKEYS - SSH PublicKey Self-Service Center</a>
16+
</nav>
17+
{{ this }}
18+
</body>
19+
</html>

0 commit comments

Comments
 (0)