Skip to content

Commit cb3b889

Browse files
committed
Optimize performance by not reading whole totp file to memory every time
1 parent 35721be commit cb3b889

File tree

3 files changed

+33
-42
lines changed

3 files changed

+33
-42
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "nginx-auth-server"
3-
version = "1.0.1"
3+
version = "1.0.2"
44
authors = ["Steffen Manzer"]
55
edition = '2024'
66

src/main.rs

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use pam::Client;
99
use serde::{Serialize, Deserialize};
1010
use std::{collections::HashMap, sync::{Arc, Mutex}, time::{SystemTime, UNIX_EPOCH}};
1111
use std::fs;
12-
use std::io::prelude::*;
12+
use std::io::{BufRead, BufReader, prelude::*};
1313
use std::os::unix::fs::OpenOptionsExt;
1414
use tokio::time::{interval, Duration as TokioDuration};
1515
use uuid::Uuid;
@@ -156,48 +156,39 @@ async fn handle_login(
156156
return Err((StatusCode::UNAUTHORIZED, "Invalid username or password"));
157157
}
158158

159-
// Check TOTP
160-
let totp_file = fs::read_to_string(&ARGS.shadow_file).unwrap();
161-
let mut totp_map = HashMap::new();
162-
163-
for (_, line) in totp_file.lines().enumerate() {
164-
if line.is_empty() {
165-
continue
166-
}
167-
let mut parts = line.splitn(2, ',');
168-
let username = parts.next().unwrap_or("").trim();
169-
let secret = parts.next().unwrap_or("").trim();
159+
// Search TOTP secret in shadow_file
160+
let file = fs::File::open(ARGS.shadow_file.clone()).unwrap();
161+
let reader = BufReader::new(file);
162+
for line in reader.lines() {
163+
if let Some((user, secret)) = line.unwrap().split_once(',') {
164+
165+
// Username found
166+
if user == &form.username {
167+
let code: u32 = form.totp.parse().unwrap_or(0);
168+
let totp = TOTP::from_base32(secret).unwrap();
169+
if !totp.verify(code, 30, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()) {
170+
println!("Login denied: Invalid TOTP for {}", &form.username);
171+
return Err((StatusCode::UNAUTHORIZED, "Invalid TOTP"))
172+
}
170173

171-
if !username.is_empty() && !secret.is_empty() {
172-
totp_map.insert(username.to_string(), secret.to_string());
173-
}
174-
}
175-
176-
let totp_map = Arc::new(totp_map);
177-
178-
if let Some(user_entry) = totp_map.get(&form.username) {
179-
let code: u32 = form.totp.parse().unwrap_or(0);
180-
let totp = TOTP::from_base32(user_entry).unwrap();
181-
if !totp.verify(code, 30, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()) {
182-
println!("Login denied: Invalid TOTP for {}", &form.username);
183-
return Err((StatusCode::UNAUTHORIZED, "Invalid TOTP"))
184-
}
185-
186-
// Create session
187-
let session_id = Uuid::new_v4().to_string();
188-
let expires = Utc::now() + ARGS.session_lifetime;
189-
sessions.lock().unwrap().insert(session_id.clone(), SessionData { username: form.username.clone(), expires_at: expires });
174+
// Create session
175+
let session_id = Uuid::new_v4().to_string();
176+
let expires = Utc::now() + ARGS.session_lifetime;
177+
sessions.lock().unwrap().insert(session_id.clone(), SessionData { username: form.username.clone(), expires_at: expires });
190178

191-
// Persist sessions in file, if enabled
192-
save_sessions_to_file(&sessions);
179+
// Persist sessions in file, if enabled
180+
save_sessions_to_file(&sessions);
193181

194-
println!("Login successful: {}", &form.username);
195-
let offset_dt = OffsetDateTime::from_unix_timestamp(expires.timestamp())
196-
.expect("valid timestamp");
197-
return Ok((
198-
jar.add(Cookie::build(("nginx-auth", session_id)).path("/").http_only(true).expires(offset_dt)),
199-
"Login successful"
200-
));
182+
println!("Login successful: {}", &form.username);
183+
let offset_dt = OffsetDateTime::from_unix_timestamp(expires.timestamp())
184+
.expect("valid timestamp");
185+
186+
return Ok((
187+
jar.add(Cookie::build(("nginx-auth", session_id)).path("/").http_only(true).expires(offset_dt)),
188+
"Login successful"
189+
));
190+
}
191+
}
201192
}
202193

203194
println!("Login denied: Missing TOTP {}", &form.username);

0 commit comments

Comments
 (0)