Aldonu aŭtentigo per pasvorto
Tio postulas kampojn por la pasvorto kaj la salo en la datumbazo.
This commit is contained in:
parent
823a701a2f
commit
f4164a62c4
|
@ -46,6 +46,15 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "buf_redux"
|
name = "buf_redux"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
|
@ -92,6 +101,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -101,6 +119,17 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer 0.10.0",
|
||||||
|
"crypto-common",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fallible-iterator"
|
name = "fallible-iterator"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -403,7 +432,9 @@ name = "kampanja-kontrolada-servilo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"rand 0.8.4",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
"sha2",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -833,13 +864,24 @@ version = "0.9.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
|
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer 0.9.0",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"digest",
|
"digest 0.9.0",
|
||||||
"opaque-debug",
|
"opaque-debug",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest 0.10.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
|
@ -7,7 +7,9 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { version = "1" }
|
anyhow = { version = "1" }
|
||||||
|
rand = { version = "0.8" }
|
||||||
rusqlite = { version = "0.26" }
|
rusqlite = { version = "0.26" }
|
||||||
|
sha2 = { version = "0.10" }
|
||||||
thiserror = { version = "1" }
|
thiserror = { version = "1" }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
use crate::datumbazo::Datumbazo;
|
use crate::datumbazo::Datumbazo;
|
||||||
use rusqlite::OptionalExtension;
|
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||||
|
use rusqlite::{
|
||||||
|
params,
|
||||||
|
types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef},
|
||||||
|
OptionalExtension, ToSql,
|
||||||
|
};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
|
@ -10,24 +16,24 @@ use uuid::{adapter::Hyphenated, Uuid};
|
||||||
use warp::{reject, reject::Reject, Filter, Rejection};
|
use warp::{reject, reject::Reject, Filter, Rejection};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Ĵetono(String);
|
pub struct SesiaĴetono(String);
|
||||||
|
|
||||||
impl From<&str> for Ĵetono {
|
impl From<&str> for SesiaĴetono {
|
||||||
fn from(s: &str) -> Self {
|
fn from(s: &str) -> Self {
|
||||||
Ĵetono(s.to_owned())
|
SesiaĴetono(s.to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Ĵetono {
|
impl FromStr for SesiaĴetono {
|
||||||
type Err = Infallible;
|
type Err = Infallible;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(Ĵetono(s.to_owned()))
|
Ok(SesiaĴetono(s.to_owned()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Ĵetono> for String {
|
impl From<SesiaĴetono> for String {
|
||||||
fn from(s: Ĵetono) -> Self {
|
fn from(s: SesiaĴetono) -> Self {
|
||||||
s.0.clone()
|
s.0.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +53,17 @@ impl From<UzantIdentigilo> for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromSql for UzantIdentigilo {
|
||||||
|
fn column_result(val: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
|
match val {
|
||||||
|
ValueRef::Text(t) => Ok(UzantIdentigilo::from(
|
||||||
|
String::from_utf8(Vec::from(t)).unwrap().as_ref(),
|
||||||
|
)),
|
||||||
|
_ => Err(FromSqlError::InvalidType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Uzantnomo(String);
|
pub struct Uzantnomo(String);
|
||||||
|
|
||||||
|
@ -56,47 +73,177 @@ impl From<&str> for Uzantnomo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Uzantnomo> for String {
|
||||||
|
fn from(s: &Uzantnomo) -> Self {
|
||||||
|
s.0.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Uzantnomo> for String {
|
impl From<Uzantnomo> for String {
|
||||||
fn from(s: Uzantnomo) -> Self {
|
fn from(s: Uzantnomo) -> Self {
|
||||||
s.0.clone()
|
s.0.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AŭtentigoDB: Send {
|
impl FromSql for Uzantnomo {
|
||||||
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<(UzantIdentigilo, Uzantnomo)>;
|
fn column_result(val: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
|
match val {
|
||||||
|
ValueRef::Text(t) => Ok(Uzantnomo::from(
|
||||||
|
String::from_utf8(Vec::from(t)).unwrap().as_ref(),
|
||||||
|
)),
|
||||||
|
_ => Err(FromSqlError::InvalidType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn kreu_ĵetono(&mut self, uzantnomo: Uzantnomo) -> Ĵetono;
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Pasvorto(String);
|
||||||
|
|
||||||
|
impl Pasvorto {
|
||||||
|
fn haku(&self, salo: &Salo) -> HakitaPasvorto {
|
||||||
|
let mut haketilo = Sha256::new();
|
||||||
|
haketilo.update(String::from(self).as_bytes());
|
||||||
|
haketilo.update(salo);
|
||||||
|
HakitaPasvorto(Vec::from(haketilo.finalize().as_slice()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Pasvorto {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
Pasvorto(s.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Pasvorto> for String {
|
||||||
|
fn from(s: &Pasvorto) -> Self {
|
||||||
|
s.0.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Pasvorto> for String {
|
||||||
|
fn from(s: Pasvorto) -> Self {
|
||||||
|
s.0.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
struct HakitaPasvorto(Vec<u8>);
|
||||||
|
|
||||||
|
impl ToSql for HakitaPasvorto {
|
||||||
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
|
||||||
|
Ok(ToSqlOutput::Borrowed(ValueRef::Blob(self.0.as_ref())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromSql for HakitaPasvorto {
|
||||||
|
fn column_result(val: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
|
match val {
|
||||||
|
ValueRef::Blob(t) => Ok(HakitaPasvorto(Vec::from(t))),
|
||||||
|
_ => Err(FromSqlError::InvalidType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Salo(Vec<u8>);
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Salo {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSql for Salo {
|
||||||
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
|
||||||
|
Ok(ToSqlOutput::Borrowed(ValueRef::Blob(self.0.as_ref())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromSql for Salo {
|
||||||
|
fn column_result(val: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
|
match val {
|
||||||
|
ValueRef::Blob(t) => Ok(Salo(Vec::from(t))),
|
||||||
|
_ => Err(FromSqlError::InvalidType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AŭtentigoDB: Send {
|
||||||
|
fn kreu_uzanton(&mut self, uzantnomo: Uzantnomo, pasvorto: Pasvorto) -> UzantIdentigilo;
|
||||||
|
|
||||||
|
fn kreu_sesion(&mut self, uzantnomo: &Uzantnomo) -> SesiaĴetono;
|
||||||
|
|
||||||
|
fn ŝanĝu_pasvorton(&mut self, identigilo: &UzantIdentigilo, pasvorto: Pasvorto);
|
||||||
|
|
||||||
|
fn aŭtentigu_per_pasvorto(
|
||||||
|
&self,
|
||||||
|
uzantnomo: &Uzantnomo,
|
||||||
|
pasvorto: &Pasvorto,
|
||||||
|
) -> Option<UzantIdentigilo>;
|
||||||
|
|
||||||
|
fn aŭtentigu_per_sesio(&self, ĵetono: &SesiaĴetono) -> Option<(UzantIdentigilo, Uzantnomo)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MemAŭtentigo {
|
pub struct MemAŭtentigo {
|
||||||
sesioj: HashMap<Ĵetono, UzantIdentigilo>,
|
|
||||||
uzantoj: HashMap<UzantIdentigilo, Uzantnomo>,
|
|
||||||
inversa_uzantoj: HashMap<Uzantnomo, UzantIdentigilo>,
|
inversa_uzantoj: HashMap<Uzantnomo, UzantIdentigilo>,
|
||||||
|
pasvortoj: HashMap<UzantIdentigilo, Pasvorto>,
|
||||||
|
sesioj: HashMap<SesiaĴetono, UzantIdentigilo>,
|
||||||
|
uzantoj: HashMap<UzantIdentigilo, Uzantnomo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemAŭtentigo {
|
impl MemAŭtentigo {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
inversa_uzantoj: HashMap::new(),
|
||||||
|
pasvortoj: HashMap::new(),
|
||||||
sesioj: HashMap::new(),
|
sesioj: HashMap::new(),
|
||||||
uzantoj: HashMap::new(),
|
uzantoj: HashMap::new(),
|
||||||
inversa_uzantoj: HashMap::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AŭtentigoDB for MemAŭtentigo {
|
impl AŭtentigoDB for MemAŭtentigo {
|
||||||
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<(UzantIdentigilo, Uzantnomo)> {
|
fn kreu_uzanton(&mut self, uzantnomo: Uzantnomo, pasvorto: Pasvorto) -> UzantIdentigilo {
|
||||||
|
let uzant_id =
|
||||||
|
UzantIdentigilo::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
|
||||||
|
self.uzantoj.insert(uzant_id.clone(), uzantnomo.clone());
|
||||||
|
self.pasvortoj.insert(uzant_id.clone(), pasvorto);
|
||||||
|
self.inversa_uzantoj.insert(uzantnomo, uzant_id.clone());
|
||||||
|
uzant_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kreu_sesion(&mut self, uzantnomo: &Uzantnomo) -> SesiaĴetono {
|
||||||
|
let identigilo = self.inversa_uzantoj.get(&uzantnomo).cloned().unwrap();
|
||||||
|
let ĵetono =
|
||||||
|
SesiaĴetono::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
|
||||||
|
self.sesioj.insert(ĵetono.clone(), identigilo);
|
||||||
|
ĵetono
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ŝanĝu_pasvorton(&mut self, identigilo: &UzantIdentigilo, pasvorto: Pasvorto) {
|
||||||
|
self.pasvortoj.insert(identigilo.clone(), pasvorto);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn aŭtentigu_per_pasvorto(
|
||||||
|
&self,
|
||||||
|
uzantnomo: &Uzantnomo,
|
||||||
|
pasvorto: &Pasvorto,
|
||||||
|
) -> Option<UzantIdentigilo> {
|
||||||
|
self.inversa_uzantoj.get(&uzantnomo).and_then(|id| {
|
||||||
|
self.pasvortoj.get(id).and_then(|kandidato| {
|
||||||
|
if *pasvorto == *kandidato {
|
||||||
|
Some(id.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn aŭtentigu_per_sesio(&self, ĵetono: &SesiaĴetono) -> Option<(UzantIdentigilo, Uzantnomo)> {
|
||||||
let identigilo = self.sesioj.get(&ĵetono).cloned()?;
|
let identigilo = self.sesioj.get(&ĵetono).cloned()?;
|
||||||
let uzantnomo = self.uzantoj.get(&identigilo).cloned()?;
|
let uzantnomo = self.uzantoj.get(&identigilo).cloned()?;
|
||||||
Some((identigilo, uzantnomo))
|
Some((identigilo, uzantnomo))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kreu_ĵetono(&mut self, uzantnomo: Uzantnomo) -> Ĵetono {
|
|
||||||
let identigilo = self.inversa_uzantoj.get(&uzantnomo).cloned().unwrap();
|
|
||||||
let ĵetono = Ĵetono::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
|
|
||||||
self.sesioj.insert(ĵetono.clone(), identigilo);
|
|
||||||
ĵetono
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DBAŭtentigo {
|
pub struct DBAŭtentigo {
|
||||||
|
@ -110,26 +257,50 @@ impl DBAŭtentigo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AŭtentigoDB for DBAŭtentigo {
|
impl AŭtentigoDB for DBAŭtentigo {
|
||||||
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<(UzantIdentigilo, Uzantnomo)> {
|
fn kreu_uzanton(&mut self, uzantnomo: Uzantnomo, pasvorto: Pasvorto) -> UzantIdentigilo {
|
||||||
let konekto = self.pool.konektu().unwrap();
|
let mut konekto = self.pool.konektu().unwrap();
|
||||||
konekto
|
let tr = konekto.transaction().unwrap();
|
||||||
|
|
||||||
|
let identigilo =
|
||||||
|
UzantIdentigilo::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
|
||||||
|
|
||||||
|
let cnt: usize = tr
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT uzantoj.id, uzantoj.nomo FROM sesioj INNER JOIN uzantoj on sesioj.uzanto == uzantoj.id WHERE sesioj.id = ?",
|
"SELECT count(*) from uzantoj WHERE nomo = ?",
|
||||||
[String::from(ĵetono)],
|
params![String::from(uzantnomo.clone())],
|
||||||
|row| {
|
|row| row.get("count(*)"),
|
||||||
let identigilo = row.get("id")
|
|
||||||
.map(|s: String| UzantIdentigilo::from(s.as_str())).unwrap();
|
|
||||||
let nomo = row.get("nomo")
|
|
||||||
.map(|s: String| Uzantnomo::from(s.as_str())).unwrap();
|
|
||||||
Ok((identigilo, nomo))
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
.optional()
|
.unwrap();
|
||||||
.unwrap()
|
if cnt > 0 {
|
||||||
|
panic!("uzanto jam ekzistas");
|
||||||
|
} else {
|
||||||
|
let salo = Salo(
|
||||||
|
thread_rng()
|
||||||
|
.sample_iter(&Alphanumeric)
|
||||||
|
.take(10)
|
||||||
|
.collect::<Vec<u8>>(),
|
||||||
|
);
|
||||||
|
let pasvorto = pasvorto.haku(&salo);
|
||||||
|
tr.execute(
|
||||||
|
"INSERT INTO uzantoj VALUES(?, ?, ?, ?)",
|
||||||
|
params![
|
||||||
|
String::from(identigilo.clone()),
|
||||||
|
String::from(uzantnomo),
|
||||||
|
pasvorto,
|
||||||
|
salo
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.commit().unwrap();
|
||||||
|
|
||||||
|
identigilo
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kreu_ĵetono(&mut self, uzantnomo: Uzantnomo) -> Ĵetono {
|
fn kreu_sesion(&mut self, uzantnomo: &Uzantnomo) -> SesiaĴetono {
|
||||||
let ĵetono = Ĵetono::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
|
let ĵetono =
|
||||||
|
SesiaĴetono::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
|
||||||
let mut konekto = self.pool.konektu().unwrap();
|
let mut konekto = self.pool.konektu().unwrap();
|
||||||
let tr = konekto.transaction().unwrap();
|
let tr = konekto.transaction().unwrap();
|
||||||
let uzanta_id: Option<String> = tr
|
let uzanta_id: Option<String> = tr
|
||||||
|
@ -153,6 +324,68 @@ impl AŭtentigoDB for DBAŭtentigo {
|
||||||
tr.commit().unwrap();
|
tr.commit().unwrap();
|
||||||
ĵetono
|
ĵetono
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ŝanĝu_pasvorton(&mut self, identigilo: &UzantIdentigilo, pasvorto: Pasvorto) {}
|
||||||
|
|
||||||
|
fn aŭtentigu_per_pasvorto(
|
||||||
|
&self,
|
||||||
|
uzantnomo: &Uzantnomo,
|
||||||
|
pasvorto: &Pasvorto,
|
||||||
|
) -> Option<UzantIdentigilo> {
|
||||||
|
let konekto = self.pool.konektu().unwrap();
|
||||||
|
let mut demando = konekto
|
||||||
|
.prepare_cached("SELECT * FROM uzantoj WHERE nomo = ?")
|
||||||
|
.unwrap();
|
||||||
|
let rezultoj = demando.query_map(params![String::from(uzantnomo)], |row| {
|
||||||
|
let id = row.get("id")?;
|
||||||
|
let nomo = row.get("nomo")?;
|
||||||
|
let pasvorto = row.get("pasvorto")?;
|
||||||
|
let salo = row.get("pasvortsalo")?;
|
||||||
|
Ok((id, nomo, pasvorto, salo))
|
||||||
|
});
|
||||||
|
|
||||||
|
let rows: Vec<(UzantIdentigilo, Uzantnomo, HakitaPasvorto, Salo)> = match rezultoj {
|
||||||
|
Ok(r) => {
|
||||||
|
let mut rows = Vec::new();
|
||||||
|
for row in r {
|
||||||
|
let (id, nomo, pasvorto, salo) = row.unwrap();
|
||||||
|
rows.push((id, nomo, pasvorto, salo));
|
||||||
|
}
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
Err(_) => panic!("eraro en datumbazo"),
|
||||||
|
};
|
||||||
|
|
||||||
|
match rows.len() {
|
||||||
|
1 => {
|
||||||
|
let (ref identigilo, _, ref hakita_pasvorto, ref salo) = rows[0];
|
||||||
|
if pasvorto.haku(&salo) == *hakita_pasvorto {
|
||||||
|
Some(identigilo.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0 => None,
|
||||||
|
_ => panic!("pli ol unu kongruo trovis por uzantnomo"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn aŭtentigu_per_sesio(&self, ĵetono: &SesiaĴetono) -> Option<(UzantIdentigilo, Uzantnomo)> {
|
||||||
|
let konekto = self.pool.konektu().unwrap();
|
||||||
|
konekto.query_row(
|
||||||
|
"SELECT uzantoj.id, uzantoj.nomo FROM sesioj INNER JOIN uzantoj on sesioj.uzanto == uzantoj.id WHERE sesioj.id = ?",
|
||||||
|
params![String::from(ĵetono.clone())],
|
||||||
|
|row| {
|
||||||
|
let identigilo = row.get("id")
|
||||||
|
.map(|s: String| UzantIdentigilo::from(s.as_str())).unwrap();
|
||||||
|
let nomo = row.get("nomo")
|
||||||
|
.map(|s: String| Uzantnomo::from(s.as_str())).unwrap();
|
||||||
|
Ok((identigilo, nomo))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -166,10 +399,10 @@ pub fn kun_aŭtentigo(
|
||||||
let auth_ctx = auth_ctx.clone();
|
let auth_ctx = auth_ctx.clone();
|
||||||
warp::header("authentication").and_then({
|
warp::header("authentication").and_then({
|
||||||
let auth_ctx = auth_ctx.clone();
|
let auth_ctx = auth_ctx.clone();
|
||||||
move |text| {
|
move |text: SesiaĴetono| {
|
||||||
let auth_ctx = auth_ctx.clone();
|
let auth_ctx = auth_ctx.clone();
|
||||||
async move {
|
async move {
|
||||||
match auth_ctx.read().unwrap().aŭtentigu(text) {
|
match auth_ctx.read().unwrap().aŭtentigu_per_sesio(&text) {
|
||||||
Some(salutiloj) => Ok(salutiloj),
|
Some(salutiloj) => Ok(salutiloj),
|
||||||
None => Err(reject::custom(AŭtentigoPostulas)),
|
None => Err(reject::custom(AŭtentigoPostulas)),
|
||||||
}
|
}
|
||||||
|
@ -177,3 +410,22 @@ pub fn kun_aŭtentigo(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ĝi_povas_krei_uzanto() {
|
||||||
|
let vojo = NamedTempFile::new().unwrap().into_temp_path();
|
||||||
|
let datumbazo = Datumbazo::kreu(vojo.to_path_buf()).unwrap();
|
||||||
|
let mut aŭtentigo = DBAŭtentigo::kreu(datumbazo);
|
||||||
|
let identigilo =
|
||||||
|
aŭtentigo.kreu_uzanton(Uzantnomo::from("savanni"), Pasvorto::from("abcdefg"));
|
||||||
|
|
||||||
|
let aŭtentita_identigilo = aŭtentigo
|
||||||
|
.aŭtentigu_per_pasvorto(&Uzantnomo::from("savanni"), &Pasvorto::from("abcdefg"));
|
||||||
|
assert_eq!(aŭtentita_identigilo, Some(identigilo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl Datumbazo {
|
||||||
println!("versio: {}", versio);
|
println!("versio: {}", versio);
|
||||||
if versio == 0 {
|
if versio == 0 {
|
||||||
tx.execute_batch(
|
tx.execute_batch(
|
||||||
"CREATE TABLE uzantoj (id string primary key, nomo text);
|
"CREATE TABLE uzantoj (id string primary key, nomo text, pasvorto text, pasvortsalo text);
|
||||||
CREATE TABLE rajtoj (uzanto string, rajto string, foreign key(uzanto) references uzanto(id));
|
CREATE TABLE rajtoj (uzanto string, rajto string, foreign key(uzanto) references uzanto(id));
|
||||||
CREATE TABLE sesioj (id string primary key not null, uzanto string, foreign key(uzanto) references uzantoj(id));
|
CREATE TABLE sesioj (id string primary key not null, uzanto string, foreign key(uzanto) references uzantoj(id));
|
||||||
PRAGMA user_version = 1;",
|
PRAGMA user_version = 1;",
|
||||||
|
@ -97,20 +97,20 @@ mod test {
|
||||||
let mut konekto = datumbazo.konektu().unwrap();
|
let mut konekto = datumbazo.konektu().unwrap();
|
||||||
let tr = konekto.transaction().unwrap();
|
let tr = konekto.transaction().unwrap();
|
||||||
tr.execute(
|
tr.execute(
|
||||||
"INSERT INTO uzantoj VALUES(?, ?)",
|
"INSERT INTO uzantoj VALUES(?, ?, ?, ?)",
|
||||||
params![1, String::from("mia-uzantnomo")],
|
params!["abcdfeg", "mia-uzantnomo", "pasvorto", "abcdefg"],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
tr.commit().unwrap();
|
tr.commit().unwrap();
|
||||||
|
|
||||||
let konekto = datumbazo.konektu().unwrap();
|
let konekto = datumbazo.konektu().unwrap();
|
||||||
let id: Option<u32> = konekto
|
let id: Option<String> = konekto
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT id FROM uzantoj WHERE nomo = ?",
|
"SELECT id FROM uzantoj WHERE nomo = ?",
|
||||||
[String::from("mia-uzantnomo")],
|
[String::from("mia-uzantnomo")],
|
||||||
|row| row.get("id"),
|
|row| row.get("id"),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(id, Some(1));
|
assert_eq!(id, Some(String::from("abcdfeg")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub async fn main() {
|
||||||
let ĵetono = auth_ctx
|
let ĵetono = auth_ctx
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.kreu_ĵetono(Uzantnomo::from("savanni"));
|
.kreu_sesion(&Uzantnomo::from("savanni"));
|
||||||
println!("ĵetono: {}", String::from(ĵetono));
|
println!("ĵetono: {}", String::from(ĵetono));
|
||||||
let rajtigo = Arc::new(RwLock::new(DBRajtigo::kreu(db)));
|
let rajtigo = Arc::new(RwLock::new(DBRajtigo::kreu(db)));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue