password change
This commit is contained in:
+64
-2
@@ -117,7 +117,7 @@ pub fn login(tx: &mut Transaction, name: &String, password: &String) -> Result<A
|
||||
Ok(Account { id, name, balance, subscribed })
|
||||
}
|
||||
|
||||
pub fn new_token(tx: &mut Transaction, id: Uuid) -> Result<String, Error> {
|
||||
pub fn new_token(tx: &mut Transaction, id: Uuid) -> Result<String, MnmlHttpError> {
|
||||
let mut rng = thread_rng();
|
||||
let token: String = iter::repeat(())
|
||||
.map(|()| rng.sample(Alphanumeric))
|
||||
@@ -136,11 +136,73 @@ pub fn new_token(tx: &mut Transaction, id: Uuid) -> Result<String, Error> {
|
||||
.query(query, &[&token, &id])?;
|
||||
|
||||
result.iter().next()
|
||||
.ok_or(format_err!("account not updated {:?}", id))?;
|
||||
.ok_or(MnmlHttpError::Unauthorized)?;
|
||||
|
||||
Ok(token)
|
||||
}
|
||||
|
||||
pub fn set_password(tx: &mut Transaction, id: Uuid, current: &String, password: &String) -> Result<String, MnmlHttpError> {
|
||||
if password.len() < PASSWORD_MIN_LEN {
|
||||
return Err(MnmlHttpError::PasswordUnacceptable);
|
||||
}
|
||||
|
||||
let query = "
|
||||
SELECT id, password
|
||||
FROM accounts
|
||||
WHERE id = $1
|
||||
";
|
||||
|
||||
let result = tx
|
||||
.query(query, &[&id])?;
|
||||
|
||||
let row = match result.iter().next() {
|
||||
Some(row) => row,
|
||||
None => {
|
||||
let mut rng = thread_rng();
|
||||
let garbage: String = iter::repeat(())
|
||||
.map(|()| rng.sample(Alphanumeric))
|
||||
.take(64)
|
||||
.collect();
|
||||
|
||||
// verify garbage to prevent timing attacks
|
||||
verify(garbage.clone(), &garbage).ok();
|
||||
return Err(MnmlHttpError::AccountNotFound);
|
||||
},
|
||||
};
|
||||
|
||||
let id: Uuid = row.get(0);
|
||||
let db_pw: String = row.get(1);
|
||||
|
||||
if !verify(current, &db_pw)? {
|
||||
return Err(MnmlHttpError::PasswordNotMatch);
|
||||
}
|
||||
|
||||
let rounds = 8;
|
||||
let password = hash(&password, rounds)?;
|
||||
|
||||
let query = "
|
||||
UPDATE accounts
|
||||
SET password = $1, updated_at = now()
|
||||
WHERE id = $2
|
||||
RETURNING id, name;
|
||||
";
|
||||
|
||||
let result = tx
|
||||
.query(query, &[&password, &id])?;
|
||||
|
||||
let row = match result.iter().next() {
|
||||
Some(row) => row,
|
||||
None => return Err(MnmlHttpError::DbError),
|
||||
};
|
||||
|
||||
let name: String = row.get(1);
|
||||
|
||||
info!("password updated name={:?} id={:?}", name, id);
|
||||
|
||||
new_token(tx, id)
|
||||
}
|
||||
|
||||
|
||||
pub fn credit(tx: &mut Transaction, id: Uuid, credits: i64) -> Result<String, Error> {
|
||||
let query = "
|
||||
UPDATE accounts
|
||||
|
||||
+31
-2
@@ -221,7 +221,7 @@ fn login(req: &mut Request) -> IronResult<Response> {
|
||||
|
||||
match account::login(&mut tx, ¶ms.name, ¶ms.password) {
|
||||
Ok(a) => {
|
||||
let token = account::new_token(&mut tx, a.id).or(Err(MnmlHttpError::ServerError))?;
|
||||
let token = account::new_token(&mut tx, a.id)?;
|
||||
tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
||||
Ok(token_res(token))
|
||||
},
|
||||
@@ -239,7 +239,7 @@ fn logout(req: &mut Request) -> IronResult<Response> {
|
||||
let db = state.pool.get().or(Err(MnmlHttpError::DbError))?;
|
||||
let mut tx = db.transaction().or(Err(MnmlHttpError::DbError))?;
|
||||
|
||||
account::new_token(&mut tx, a.id).or(Err(MnmlHttpError::Unauthorized))?;
|
||||
account::new_token(&mut tx, a.id)?;
|
||||
|
||||
tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
||||
|
||||
@@ -252,6 +252,33 @@ fn logout(req: &mut Request) -> IronResult<Response> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Deserialize)]
|
||||
struct SetPassword {
|
||||
current: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
fn set_password(req: &mut Request) -> IronResult<Response> {
|
||||
let state = req.get::<Read<State>>().unwrap();
|
||||
let params = match req.get::<bodyparser::Struct<SetPassword>>() {
|
||||
Ok(Some(b)) => b,
|
||||
_ => return Err(IronError::from(MnmlHttpError::BadRequest)),
|
||||
};
|
||||
|
||||
match req.extensions.get::<account::Account>() {
|
||||
Some(a) => {
|
||||
let db = state.pool.get().or(Err(MnmlHttpError::DbError))?;
|
||||
let mut tx = db.transaction().or(Err(MnmlHttpError::DbError))?;
|
||||
|
||||
let token = account::set_password(&mut tx, a.id, ¶ms.current, ¶ms.password)?;
|
||||
|
||||
tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
||||
|
||||
Ok(token_res(token))
|
||||
},
|
||||
None => Err(IronError::from(MnmlHttpError::Unauthorized)),
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_BODY_LENGTH: usize = 1024 * 1024 * 10;
|
||||
|
||||
@@ -269,6 +296,8 @@ pub fn start(pool: PgPool) {
|
||||
router.post("/api/account/login", login, "login");
|
||||
router.post("/api/account/logout", logout, "logout");
|
||||
router.post("/api/account/register", register, "register");
|
||||
router.post("/api/account/password", set_password, "set_password");
|
||||
router.post("/api/account/email", logout, "email");
|
||||
|
||||
// payments
|
||||
router.post("/api/payments/stripe", stripe, "stripe");
|
||||
|
||||
Reference in New Issue
Block a user