1// use super::{
2// db::{self, UserId},
3// errors::TideResultExt,
4// };
5// use crate::Request;
6// use anyhow::{anyhow, Context};
7// use rand::thread_rng;
8// use rpc::auth as zed_auth;
9// use scrypt::{
10// password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
11// Scrypt,
12// };
13// use std::convert::TryFrom;
14// use surf::StatusCode;
15// use tide::Error;
16
17// pub async fn process_auth_header(request: &Request) -> tide::Result<UserId> {
18// let mut auth_header = request
19// .header("Authorization")
20// .ok_or_else(|| {
21// Error::new(
22// StatusCode::BadRequest,
23// anyhow!("missing authorization header"),
24// )
25// })?
26// .last()
27// .as_str()
28// .split_whitespace();
29// let user_id = UserId(auth_header.next().unwrap_or("").parse().map_err(|_| {
30// Error::new(
31// StatusCode::BadRequest,
32// anyhow!("missing user id in authorization header"),
33// )
34// })?);
35// let access_token = auth_header.next().ok_or_else(|| {
36// Error::new(
37// StatusCode::BadRequest,
38// anyhow!("missing access token in authorization header"),
39// )
40// })?;
41
42// let state = request.state().clone();
43// let mut credentials_valid = false;
44// for password_hash in state.db.get_access_token_hashes(user_id).await? {
45// if verify_access_token(&access_token, &password_hash)? {
46// credentials_valid = true;
47// break;
48// }
49// }
50
51// if !credentials_valid {
52// Err(Error::new(
53// StatusCode::Unauthorized,
54// anyhow!("invalid credentials"),
55// ))?;
56// }
57
58// Ok(user_id)
59// }
60
61// const MAX_ACCESS_TOKENS_TO_STORE: usize = 8;
62
63// pub async fn create_access_token(db: &dyn db::Db, user_id: UserId) -> tide::Result<String> {
64// let access_token = zed_auth::random_token();
65// let access_token_hash =
66// hash_access_token(&access_token).context("failed to hash access token")?;
67// db.create_access_token_hash(user_id, &access_token_hash, MAX_ACCESS_TOKENS_TO_STORE)
68// .await?;
69// Ok(access_token)
70// }
71
72// fn hash_access_token(token: &str) -> tide::Result<String> {
73// // Avoid slow hashing in debug mode.
74// let params = if cfg!(debug_assertions) {
75// scrypt::Params::new(1, 1, 1).unwrap()
76// } else {
77// scrypt::Params::recommended()
78// };
79
80// Ok(Scrypt
81// .hash_password(
82// token.as_bytes(),
83// None,
84// params,
85// &SaltString::generate(thread_rng()),
86// )?
87// .to_string())
88// }
89
90// pub fn encrypt_access_token(access_token: &str, public_key: String) -> tide::Result<String> {
91// let native_app_public_key =
92// zed_auth::PublicKey::try_from(public_key).context("failed to parse app public key")?;
93// let encrypted_access_token = native_app_public_key
94// .encrypt_string(&access_token)
95// .context("failed to encrypt access token with public key")?;
96// Ok(encrypted_access_token)
97// }
98
99// pub fn verify_access_token(token: &str, hash: &str) -> tide::Result<bool> {
100// let hash = PasswordHash::new(hash)?;
101// Ok(Scrypt.verify_password(token.as_bytes(), &hash).is_ok())
102// }