--- a/rust/hedgewars-server/src/server/database.rs Tue Apr 09 00:45:14 2019 +0200
+++ b/rust/hedgewars-server/src/server/database.rs Tue Apr 09 21:08:35 2019 +0300
@@ -1,11 +1,20 @@
use mysql;
-use mysql::{error::DriverError, error::Error, params};
+use mysql::{error::DriverError, error::Error, from_row_opt, params};
+use openssl::sha::sha1;
+
+use super::handlers::AccountInfo;
+use crate::server::handlers::Sha1Digest;
-struct AccountInfo {
- is_registered: bool,
- is_admin: bool,
- is_contributor: bool,
-}
+const GET_ACCOUNT_QUERY: &str =
+ r"SELECT CASE WHEN users.status = 1 THEN users.pass ELSE '' END,
+ (SELECT COUNT(users_roles.rid) FROM users_roles WHERE users.uid = users_roles.uid AND users_roles.rid = 3),
+ (SELECT COUNT(users_roles.rid) FROM users_roles WHERE users.uid = users_roles.uid AND users_roles.rid = 13)
+ FROM users WHERE users.name = :username";
+
+const STORE_STATS_QUERY: &str = r"INSERT INTO gameserver_stats
+ (players, rooms, last_update)
+ VALUES
+ (:players, :rooms, UNIX_TIMESTAMP())";
struct ServerStatistics {
rooms: u32,
@@ -14,47 +23,63 @@
struct Achievements {}
-trait DatabaseInterface {
- fn check_account(username: &str, password: &str) -> AccountInfo;
- fn store_stats(stats: &ServerStatistics) -> Result<(), ()>;
- fn store_achievements(achievements: &Achievements) -> Result<(), ()>;
- fn get_replay_name(replay_id: u32) -> Result<String, ()>;
-}
-
-struct Database {
+pub struct Database {
pool: Option<mysql::Pool>,
}
impl Database {
- fn new() -> Self {
+ pub fn new() -> Self {
Self { pool: None }
}
- fn connect(&mut self, url: &str) -> Result<(), Error> {
+ pub fn connect(&mut self, url: &str) -> Result<(), Error> {
self.pool = Some(mysql::Pool::new(url)?);
Ok(())
}
- fn check_account(&mut self, username: &str, password: &str) -> AccountInfo {
- AccountInfo {
- is_registered: false,
- is_admin: false,
- is_contributor: false,
+ pub fn get_account(
+ &mut self,
+ nick: &str,
+ protocol: u16,
+ password_hash: &str,
+ client_salt: &str,
+ server_salt: &str,
+ ) -> Result<Option<AccountInfo>, Error> {
+ if let Some(pool) = &self.pool {
+ if let Some(row) = pool.first_exec(GET_ACCOUNT_QUERY, params! { "username" => nick })? {
+ let (mut password, is_admin, is_contributor) =
+ from_row_opt::<(String, i32, i32)>(row)?;
+ let client_hash = get_hash(protocol, &password, &client_salt, &server_salt);
+ let server_hash = get_hash(protocol, &password, &server_salt, &client_salt);
+ password.replace_range(.., "🦔🦔🦔🦔🦔🦔🦔🦔");
+
+ if server_hash == client_hash {
+ Ok(Some(AccountInfo {
+ is_registered: true,
+ is_admin: is_admin == 1,
+ is_contributor: is_contributor == 1,
+ server_hash,
+ }))
+ } else {
+ Ok(None)
+ }
+ } else {
+ Ok(Some(AccountInfo {
+ is_registered: false,
+ is_admin: false,
+ is_contributor: false,
+ server_hash: Sha1Digest::new([0; 20]),
+ }))
+ }
+ } else {
+ Err(DriverError::SetupError.into())
}
}
- fn store_stats(&mut self, stats: &ServerStatistics) -> Result<(), Error> {
+ pub fn store_stats(&mut self, stats: &ServerStatistics) -> Result<(), Error> {
if let Some(pool) = &self.pool {
- for mut stmt in pool
- .prepare(
- r"INSERT INTO gameserver_stats
- (players, rooms, last_update)
- VALUES
- (:players, :rooms, UNIX_TIMESTAMP())",
- )
- .into_iter()
- {
+ for mut stmt in pool.prepare(STORE_STATS_QUERY).into_iter() {
stmt.execute(params! {
"players" => stats.players,
"rooms" => stats.rooms,
@@ -66,11 +91,19 @@
}
}
- fn store_achievements(&mut self, achievements: &Achievements) -> Result<(), ()> {
+ pub fn store_achievements(&mut self, achievements: &Achievements) -> Result<(), ()> {
Ok(())
}
- fn get_replay_name(&mut self, replay_id: u32) -> Result<String, ()> {
+ pub fn get_replay_name(&mut self, replay_id: u32) -> Result<String, ()> {
Err(())
}
}
+
+fn get_hash(protocol_number: u16, web_password: &str, salt1: &str, salt2: &str) -> Sha1Digest {
+ let s = format!(
+ "{}{}{}{}{}",
+ salt1, salt2, web_password, protocol_number, "!hedgewars"
+ );
+ Sha1Digest::new(sha1(s.as_bytes()))
+}