rust/hedgewars-server/src/server/database.rs
changeset 14779 f43ab2bd76ae
parent 14457 98ef2913ec73
child 14785 a1077e8d26f4
equal deleted inserted replaced
14778:bbec6b28d072 14779:f43ab2bd76ae
     1 use mysql;
     1 use mysql;
     2 use mysql::{error::DriverError, error::Error, params};
     2 use mysql::{error::DriverError, error::Error, from_row_opt, params};
       
     3 use openssl::sha::sha1;
     3 
     4 
     4 struct AccountInfo {
     5 use super::handlers::AccountInfo;
     5     is_registered: bool,
     6 use crate::server::handlers::Sha1Digest;
     6     is_admin: bool,
     7 
     7     is_contributor: bool,
     8 const GET_ACCOUNT_QUERY: &str =
     8 }
     9     r"SELECT CASE WHEN users.status = 1 THEN users.pass ELSE '' END,
       
    10      (SELECT COUNT(users_roles.rid) FROM users_roles WHERE users.uid = users_roles.uid AND users_roles.rid = 3),
       
    11      (SELECT COUNT(users_roles.rid) FROM users_roles WHERE users.uid = users_roles.uid AND users_roles.rid = 13)
       
    12      FROM users WHERE users.name = :username";
       
    13 
       
    14 const STORE_STATS_QUERY: &str = r"INSERT INTO gameserver_stats
       
    15             (players, rooms, last_update)
       
    16             VALUES
       
    17             (:players, :rooms, UNIX_TIMESTAMP())";
     9 
    18 
    10 struct ServerStatistics {
    19 struct ServerStatistics {
    11     rooms: u32,
    20     rooms: u32,
    12     players: u32,
    21     players: u32,
    13 }
    22 }
    14 
    23 
    15 struct Achievements {}
    24 struct Achievements {}
    16 
    25 
    17 trait DatabaseInterface {
    26 pub struct Database {
    18     fn check_account(username: &str, password: &str) -> AccountInfo;
       
    19     fn store_stats(stats: &ServerStatistics) -> Result<(), ()>;
       
    20     fn store_achievements(achievements: &Achievements) -> Result<(), ()>;
       
    21     fn get_replay_name(replay_id: u32) -> Result<String, ()>;
       
    22 }
       
    23 
       
    24 struct Database {
       
    25     pool: Option<mysql::Pool>,
    27     pool: Option<mysql::Pool>,
    26 }
    28 }
    27 
    29 
    28 impl Database {
    30 impl Database {
    29     fn new() -> Self {
    31     pub fn new() -> Self {
    30         Self { pool: None }
    32         Self { pool: None }
    31     }
    33     }
    32 
    34 
    33     fn connect(&mut self, url: &str) -> Result<(), Error> {
    35     pub fn connect(&mut self, url: &str) -> Result<(), Error> {
    34         self.pool = Some(mysql::Pool::new(url)?);
    36         self.pool = Some(mysql::Pool::new(url)?);
    35 
    37 
    36         Ok(())
    38         Ok(())
    37     }
    39     }
    38 
    40 
    39     fn check_account(&mut self, username: &str, password: &str) -> AccountInfo {
    41     pub fn get_account(
    40         AccountInfo {
    42         &mut self,
    41             is_registered: false,
    43         nick: &str,
    42             is_admin: false,
    44         protocol: u16,
    43             is_contributor: false,
    45         password_hash: &str,
       
    46         client_salt: &str,
       
    47         server_salt: &str,
       
    48     ) -> Result<Option<AccountInfo>, Error> {
       
    49         if let Some(pool) = &self.pool {
       
    50             if let Some(row) = pool.first_exec(GET_ACCOUNT_QUERY, params! { "username" => nick })? {
       
    51                 let (mut password, is_admin, is_contributor) =
       
    52                     from_row_opt::<(String, i32, i32)>(row)?;
       
    53                 let client_hash = get_hash(protocol, &password, &client_salt, &server_salt);
       
    54                 let server_hash = get_hash(protocol, &password, &server_salt, &client_salt);
       
    55                 password.replace_range(.., "🦔🦔🦔🦔🦔🦔🦔🦔");
       
    56 
       
    57                 if server_hash == client_hash {
       
    58                     Ok(Some(AccountInfo {
       
    59                         is_registered: true,
       
    60                         is_admin: is_admin == 1,
       
    61                         is_contributor: is_contributor == 1,
       
    62                         server_hash,
       
    63                     }))
       
    64                 } else {
       
    65                     Ok(None)
       
    66                 }
       
    67             } else {
       
    68                 Ok(Some(AccountInfo {
       
    69                     is_registered: false,
       
    70                     is_admin: false,
       
    71                     is_contributor: false,
       
    72                     server_hash: Sha1Digest::new([0; 20]),
       
    73                 }))
       
    74             }
       
    75         } else {
       
    76             Err(DriverError::SetupError.into())
    44         }
    77         }
    45     }
    78     }
    46 
    79 
    47     fn store_stats(&mut self, stats: &ServerStatistics) -> Result<(), Error> {
    80     pub fn store_stats(&mut self, stats: &ServerStatistics) -> Result<(), Error> {
    48         if let Some(pool) = &self.pool {
    81         if let Some(pool) = &self.pool {
    49             for mut stmt in pool
    82             for mut stmt in pool.prepare(STORE_STATS_QUERY).into_iter() {
    50                 .prepare(
       
    51                     r"INSERT INTO gameserver_stats
       
    52             (players, rooms, last_update)
       
    53             VALUES
       
    54             (:players, :rooms, UNIX_TIMESTAMP())",
       
    55                 )
       
    56                 .into_iter()
       
    57             {
       
    58                 stmt.execute(params! {
    83                 stmt.execute(params! {
    59                     "players" => stats.players,
    84                     "players" => stats.players,
    60                     "rooms" => stats.rooms,
    85                     "rooms" => stats.rooms,
    61                 })?;
    86                 })?;
    62             }
    87             }
    64         } else {
    89         } else {
    65             Err(DriverError::SetupError.into())
    90             Err(DriverError::SetupError.into())
    66         }
    91         }
    67     }
    92     }
    68 
    93 
    69     fn store_achievements(&mut self, achievements: &Achievements) -> Result<(), ()> {
    94     pub fn store_achievements(&mut self, achievements: &Achievements) -> Result<(), ()> {
    70         Ok(())
    95         Ok(())
    71     }
    96     }
    72 
    97 
    73     fn get_replay_name(&mut self, replay_id: u32) -> Result<String, ()> {
    98     pub fn get_replay_name(&mut self, replay_id: u32) -> Result<String, ()> {
    74         Err(())
    99         Err(())
    75     }
   100     }
    76 }
   101 }
       
   102 
       
   103 fn get_hash(protocol_number: u16, web_password: &str, salt1: &str, salt2: &str) -> Sha1Digest {
       
   104     let s = format!(
       
   105         "{}{}{}{}{}",
       
   106         salt1, salt2, web_password, protocol_number, "!hedgewars"
       
   107     );
       
   108     Sha1Digest::new(sha1(s.as_bytes()))
       
   109 }