WIP: Get compiling with Tokio by commenting almost everything

Co-Authored-By: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
Nathan Sobo 2022-04-22 13:33:19 -06:00
parent 53bf7b61c0
commit 447c1d2f71
8 changed files with 6860 additions and 6914 deletions

View file

@ -1,179 +1,179 @@
use crate::{auth, db::UserId, AppState, Request, RequestExt as _};
// use crate::{auth, db::UserId, AppState, Request, RequestExt as _};
use async_trait::async_trait;
use serde::Deserialize;
use serde_json::json;
use std::sync::Arc;
use surf::StatusCode;
// use surf::StatusCode;
pub fn add_routes(app: &mut tide::Server<Arc<AppState>>) {
app.at("/users").get(get_users);
app.at("/users").post(create_user);
app.at("/users/:id").put(update_user);
app.at("/users/:id").delete(destroy_user);
app.at("/users/:github_login").get(get_user);
app.at("/users/:github_login/access_tokens")
.post(create_access_token);
}
// pub fn add_routes(app: &mut tide::Server<Arc<AppState>>) {
// app.at("/users").get(get_users);
// app.at("/users").post(create_user);
// app.at("/users/:id").put(update_user);
// app.at("/users/:id").delete(destroy_user);
// app.at("/users/:github_login").get(get_user);
// app.at("/users/:github_login/access_tokens")
// .post(create_access_token);
// }
async fn get_user(request: Request) -> tide::Result {
request.require_token().await?;
// async fn get_user(request: Request) -> tide::Result {
// request.require_token().await?;
let user = request
.db()
.get_user_by_github_login(request.param("github_login")?)
.await?
.ok_or_else(|| surf::Error::from_str(404, "user not found"))?;
// let user = request
// .db()
// .get_user_by_github_login(request.param("github_login")?)
// .await?
// .ok_or_else(|| surf::Error::from_str(404, "user not found"))?;
Ok(tide::Response::builder(StatusCode::Ok)
.body(tide::Body::from_json(&user)?)
.build())
}
// Ok(tide::Response::builder(StatusCode::Ok)
// .body(tide::Body::from_json(&user)?)
// .build())
// }
async fn get_users(request: Request) -> tide::Result {
request.require_token().await?;
// async fn get_users(request: Request) -> tide::Result {
// request.require_token().await?;
let users = request.db().get_all_users().await?;
// let users = request.db().get_all_users().await?;
Ok(tide::Response::builder(StatusCode::Ok)
.body(tide::Body::from_json(&users)?)
.build())
}
// Ok(tide::Response::builder(StatusCode::Ok)
// .body(tide::Body::from_json(&users)?)
// .build())
// }
async fn create_user(mut request: Request) -> tide::Result {
request.require_token().await?;
// async fn create_user(mut request: Request) -> tide::Result {
// request.require_token().await?;
#[derive(Deserialize)]
struct Params {
github_login: String,
admin: bool,
}
let params = request.body_json::<Params>().await?;
// #[derive(Deserialize)]
// struct Params {
// github_login: String,
// admin: bool,
// }
// let params = request.body_json::<Params>().await?;
let user_id = request
.db()
.create_user(&params.github_login, params.admin)
.await?;
// let user_id = request
// .db()
// .create_user(&params.github_login, params.admin)
// .await?;
let user = request.db().get_user_by_id(user_id).await?.ok_or_else(|| {
surf::Error::from_str(
StatusCode::InternalServerError,
"couldn't find the user we just created",
)
})?;
// let user = request.db().get_user_by_id(user_id).await?.ok_or_else(|| {
// surf::Error::from_str(
// StatusCode::InternalServerError,
// "couldn't find the user we just created",
// )
// })?;
Ok(tide::Response::builder(StatusCode::Ok)
.body(tide::Body::from_json(&user)?)
.build())
}
// Ok(tide::Response::builder(StatusCode::Ok)
// .body(tide::Body::from_json(&user)?)
// .build())
// }
async fn update_user(mut request: Request) -> tide::Result {
request.require_token().await?;
// async fn update_user(mut request: Request) -> tide::Result {
// request.require_token().await?;
#[derive(Deserialize)]
struct Params {
admin: bool,
}
let user_id = UserId(
request
.param("id")?
.parse::<i32>()
.map_err(|error| surf::Error::from_str(StatusCode::BadRequest, error.to_string()))?,
);
let params = request.body_json::<Params>().await?;
// #[derive(Deserialize)]
// struct Params {
// admin: bool,
// }
// let user_id = UserId(
// request
// .param("id")?
// .parse::<i32>()
// .map_err(|error| surf::Error::from_str(StatusCode::BadRequest, error.to_string()))?,
// );
// let params = request.body_json::<Params>().await?;
request
.db()
.set_user_is_admin(user_id, params.admin)
.await?;
// request
// .db()
// .set_user_is_admin(user_id, params.admin)
// .await?;
Ok(tide::Response::builder(StatusCode::Ok).build())
}
// Ok(tide::Response::builder(StatusCode::Ok).build())
// }
async fn destroy_user(request: Request) -> tide::Result {
request.require_token().await?;
let user_id = UserId(
request
.param("id")?
.parse::<i32>()
.map_err(|error| surf::Error::from_str(StatusCode::BadRequest, error.to_string()))?,
);
// async fn destroy_user(request: Request) -> tide::Result {
// request.require_token().await?;
// let user_id = UserId(
// request
// .param("id")?
// .parse::<i32>()
// .map_err(|error| surf::Error::from_str(StatusCode::BadRequest, error.to_string()))?,
// );
request.db().destroy_user(user_id).await?;
// request.db().destroy_user(user_id).await?;
Ok(tide::Response::builder(StatusCode::Ok).build())
}
// Ok(tide::Response::builder(StatusCode::Ok).build())
// }
async fn create_access_token(request: Request) -> tide::Result {
request.require_token().await?;
// async fn create_access_token(request: Request) -> tide::Result {
// request.require_token().await?;
let user = request
.db()
.get_user_by_github_login(request.param("github_login")?)
.await?
.ok_or_else(|| surf::Error::from_str(StatusCode::NotFound, "user not found"))?;
// let user = request
// .db()
// .get_user_by_github_login(request.param("github_login")?)
// .await?
// .ok_or_else(|| surf::Error::from_str(StatusCode::NotFound, "user not found"))?;
#[derive(Deserialize)]
struct QueryParams {
public_key: String,
impersonate: Option<String>,
}
// #[derive(Deserialize)]
// struct QueryParams {
// public_key: String,
// impersonate: Option<String>,
// }
let query_params: QueryParams = request.query().map_err(|_| {
surf::Error::from_str(StatusCode::UnprocessableEntity, "invalid query params")
})?;
// let query_params: QueryParams = request.query().map_err(|_| {
// surf::Error::from_str(StatusCode::UnprocessableEntity, "invalid query params")
// })?;
let mut user_id = user.id;
if let Some(impersonate) = query_params.impersonate {
if user.admin {
if let Some(impersonated_user) =
request.db().get_user_by_github_login(&impersonate).await?
{
user_id = impersonated_user.id;
} else {
return Ok(tide::Response::builder(StatusCode::UnprocessableEntity)
.body(format!(
"Can't impersonate non-existent user {}",
impersonate
))
.build());
}
} else {
return Ok(tide::Response::builder(StatusCode::Unauthorized)
.body(format!(
"Can't impersonate user {} because the real user isn't an admin",
impersonate
))
.build());
}
}
// let mut user_id = user.id;
// if let Some(impersonate) = query_params.impersonate {
// if user.admin {
// if let Some(impersonated_user) =
// request.db().get_user_by_github_login(&impersonate).await?
// {
// user_id = impersonated_user.id;
// } else {
// return Ok(tide::Response::builder(StatusCode::UnprocessableEntity)
// .body(format!(
// "Can't impersonate non-existent user {}",
// impersonate
// ))
// .build());
// }
// } else {
// return Ok(tide::Response::builder(StatusCode::Unauthorized)
// .body(format!(
// "Can't impersonate user {} because the real user isn't an admin",
// impersonate
// ))
// .build());
// }
// }
let access_token = auth::create_access_token(request.db().as_ref(), user_id).await?;
let encrypted_access_token =
auth::encrypt_access_token(&access_token, query_params.public_key.clone())?;
// let access_token = auth::create_access_token(request.db().as_ref(), user_id).await?;
// let encrypted_access_token =
// auth::encrypt_access_token(&access_token, query_params.public_key.clone())?;
Ok(tide::Response::builder(StatusCode::Ok)
.body(json!({"user_id": user_id, "encrypted_access_token": encrypted_access_token}))
.build())
}
// Ok(tide::Response::builder(StatusCode::Ok)
// .body(json!({"user_id": user_id, "encrypted_access_token": encrypted_access_token}))
// .build())
// }
#[async_trait]
pub trait RequestExt {
async fn require_token(&self) -> tide::Result<()>;
}
// #[async_trait]
// pub trait RequestExt {
// async fn require_token(&self) -> tide::Result<()>;
// }
#[async_trait]
impl RequestExt for Request {
async fn require_token(&self) -> tide::Result<()> {
let token = self
.header("Authorization")
.and_then(|header| header.get(0))
.and_then(|header| header.as_str().strip_prefix("token "))
.ok_or_else(|| surf::Error::from_str(403, "invalid authorization header"))?;
// #[async_trait]
// impl RequestExt for Request {
// async fn require_token(&self) -> tide::Result<()> {
// let token = self
// .header("Authorization")
// .and_then(|header| header.get(0))
// .and_then(|header| header.as_str().strip_prefix("token "))
// .ok_or_else(|| surf::Error::from_str(403, "invalid authorization header"))?;
if token == self.state().config.api_token {
Ok(())
} else {
Err(tide::Error::from_str(403, "invalid authorization token"))
}
}
}
// if token == self.state().config.api_token {
// Ok(())
// } else {
// Err(tide::Error::from_str(403, "invalid authorization token"))
// }
// }
// }

View file

@ -1,102 +1,102 @@
use super::{
db::{self, UserId},
errors::TideResultExt,
};
use crate::Request;
use anyhow::{anyhow, Context};
use rand::thread_rng;
use rpc::auth as zed_auth;
use scrypt::{
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Scrypt,
};
use std::convert::TryFrom;
use surf::StatusCode;
use tide::Error;
// use super::{
// db::{self, UserId},
// errors::TideResultExt,
// };
// use crate::Request;
// use anyhow::{anyhow, Context};
// use rand::thread_rng;
// use rpc::auth as zed_auth;
// use scrypt::{
// password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
// Scrypt,
// };
// use std::convert::TryFrom;
// use surf::StatusCode;
// use tide::Error;
pub async fn process_auth_header(request: &Request) -> tide::Result<UserId> {
let mut auth_header = request
.header("Authorization")
.ok_or_else(|| {
Error::new(
StatusCode::BadRequest,
anyhow!("missing authorization header"),
)
})?
.last()
.as_str()
.split_whitespace();
let user_id = UserId(auth_header.next().unwrap_or("").parse().map_err(|_| {
Error::new(
StatusCode::BadRequest,
anyhow!("missing user id in authorization header"),
)
})?);
let access_token = auth_header.next().ok_or_else(|| {
Error::new(
StatusCode::BadRequest,
anyhow!("missing access token in authorization header"),
)
})?;
// pub async fn process_auth_header(request: &Request) -> tide::Result<UserId> {
// let mut auth_header = request
// .header("Authorization")
// .ok_or_else(|| {
// Error::new(
// StatusCode::BadRequest,
// anyhow!("missing authorization header"),
// )
// })?
// .last()
// .as_str()
// .split_whitespace();
// let user_id = UserId(auth_header.next().unwrap_or("").parse().map_err(|_| {
// Error::new(
// StatusCode::BadRequest,
// anyhow!("missing user id in authorization header"),
// )
// })?);
// let access_token = auth_header.next().ok_or_else(|| {
// Error::new(
// StatusCode::BadRequest,
// anyhow!("missing access token in authorization header"),
// )
// })?;
let state = request.state().clone();
let mut credentials_valid = false;
for password_hash in state.db.get_access_token_hashes(user_id).await? {
if verify_access_token(&access_token, &password_hash)? {
credentials_valid = true;
break;
}
}
// let state = request.state().clone();
// let mut credentials_valid = false;
// for password_hash in state.db.get_access_token_hashes(user_id).await? {
// if verify_access_token(&access_token, &password_hash)? {
// credentials_valid = true;
// break;
// }
// }
if !credentials_valid {
Err(Error::new(
StatusCode::Unauthorized,
anyhow!("invalid credentials"),
))?;
}
// if !credentials_valid {
// Err(Error::new(
// StatusCode::Unauthorized,
// anyhow!("invalid credentials"),
// ))?;
// }
Ok(user_id)
}
// Ok(user_id)
// }
const MAX_ACCESS_TOKENS_TO_STORE: usize = 8;
// const MAX_ACCESS_TOKENS_TO_STORE: usize = 8;
pub async fn create_access_token(db: &dyn db::Db, user_id: UserId) -> tide::Result<String> {
let access_token = zed_auth::random_token();
let access_token_hash =
hash_access_token(&access_token).context("failed to hash access token")?;
db.create_access_token_hash(user_id, &access_token_hash, MAX_ACCESS_TOKENS_TO_STORE)
.await?;
Ok(access_token)
}
// pub async fn create_access_token(db: &dyn db::Db, user_id: UserId) -> tide::Result<String> {
// let access_token = zed_auth::random_token();
// let access_token_hash =
// hash_access_token(&access_token).context("failed to hash access token")?;
// db.create_access_token_hash(user_id, &access_token_hash, MAX_ACCESS_TOKENS_TO_STORE)
// .await?;
// Ok(access_token)
// }
fn hash_access_token(token: &str) -> tide::Result<String> {
// Avoid slow hashing in debug mode.
let params = if cfg!(debug_assertions) {
scrypt::Params::new(1, 1, 1).unwrap()
} else {
scrypt::Params::recommended()
};
// fn hash_access_token(token: &str) -> tide::Result<String> {
// // Avoid slow hashing in debug mode.
// let params = if cfg!(debug_assertions) {
// scrypt::Params::new(1, 1, 1).unwrap()
// } else {
// scrypt::Params::recommended()
// };
Ok(Scrypt
.hash_password(
token.as_bytes(),
None,
params,
&SaltString::generate(thread_rng()),
)?
.to_string())
}
// Ok(Scrypt
// .hash_password(
// token.as_bytes(),
// None,
// params,
// &SaltString::generate(thread_rng()),
// )?
// .to_string())
// }
pub fn encrypt_access_token(access_token: &str, public_key: String) -> tide::Result<String> {
let native_app_public_key =
zed_auth::PublicKey::try_from(public_key).context("failed to parse app public key")?;
let encrypted_access_token = native_app_public_key
.encrypt_string(&access_token)
.context("failed to encrypt access token with public key")?;
Ok(encrypted_access_token)
}
// pub fn encrypt_access_token(access_token: &str, public_key: String) -> tide::Result<String> {
// let native_app_public_key =
// zed_auth::PublicKey::try_from(public_key).context("failed to parse app public key")?;
// let encrypted_access_token = native_app_public_key
// .encrypt_string(&access_token)
// .context("failed to encrypt access token with public key")?;
// Ok(encrypted_access_token)
// }
pub fn verify_access_token(token: &str, hash: &str) -> tide::Result<bool> {
let hash = PasswordHash::new(hash)?;
Ok(Scrypt.verify_password(token.as_bytes(), &hash).is_ok())
}
// pub fn verify_access_token(token: &str, hash: &str) -> tide::Result<bool> {
// let hash = PasswordHash::new(hash)?;
// Ok(Scrypt.verify_password(token.as_bytes(), &hash).is_ok())
// }

View file

@ -1,11 +1,12 @@
use anyhow::Context;
use anyhow::Result;
use async_std::task::{block_on, yield_now};
use async_trait::async_trait;
use futures::executor::block_on;
use serde::Serialize;
pub use sqlx::postgres::PgPoolOptions as DbOptions;
use sqlx::{types::Uuid, FromRow};
use time::OffsetDateTime;
use tokio::task::yield_now;
macro_rules! test_support {
($self:ident, { $($token:tt)* }) => {{
@ -81,7 +82,7 @@ pub struct PostgresDb {
}
impl PostgresDb {
pub async fn new(url: &str, max_connections: u32) -> tide::Result<Self> {
pub async fn new(url: &str, max_connections: u32) -> Result<Self> {
let pool = DbOptions::new()
.max_connections(max_connections)
.connect(url)

View file

@ -2,18 +2,17 @@ mod api;
mod auth;
mod db;
mod env;
mod errors;
mod rpc;
use ::rpc::Peer;
use async_std::net::TcpListener;
use anyhow::Result;
use async_trait::async_trait;
use db::{Db, PostgresDb};
use serde::Deserialize;
use std::sync::Arc;
use tide_compress::CompressMiddleware;
use tokio::net::TcpListener;
type Request = tide::Request<Arc<AppState>>;
// type Request = tide::Request<Arc<AppState>>;
#[derive(Default, Deserialize)]
pub struct Config {
@ -28,7 +27,7 @@ pub struct AppState {
}
impl AppState {
async fn new(config: Config) -> tide::Result<Arc<Self>> {
async fn new(config: Config) -> Result<Arc<Self>> {
let db = PostgresDb::new(&config.database_url, 5).await?;
let this = Self {
@ -39,24 +38,24 @@ impl AppState {
}
}
#[async_trait]
trait RequestExt {
fn db(&self) -> &Arc<dyn Db>;
}
// #[async_trait]
// trait RequestExt {
// fn db(&self) -> &Arc<dyn Db>;
// }
#[async_trait]
impl RequestExt for Request {
fn db(&self) -> &Arc<dyn Db> {
&self.state().db
}
}
// #[async_trait]
// impl RequestExt for Request {
// fn db(&self) -> &Arc<dyn Db> {
// &self.state().db
// }
// }
#[async_std::main]
async fn main() -> tide::Result<()> {
#[tokio::main]
async fn main() -> Result<()> {
if std::env::var("LOG_JSON").is_ok() {
json_env_logger::init();
} else {
tide::log::start();
env_logger::init();
}
if let Err(error) = env::load_dotenv() {
@ -78,21 +77,17 @@ async fn main() -> tide::Result<()> {
Ok(())
}
pub async fn run_server(
state: Arc<AppState>,
rpc: Arc<Peer>,
listener: TcpListener,
) -> tide::Result<()> {
let mut app = tide::with_state(state.clone());
rpc::add_routes(&mut app, &rpc);
pub async fn run_server(state: Arc<AppState>, rpc: Arc<Peer>, listener: TcpListener) -> Result<()> {
// let mut app = tide::with_state(state.clone());
// rpc::add_routes(&mut app, &rpc);
let mut web = tide::with_state(state.clone());
web.with(CompressMiddleware::new());
api::add_routes(&mut web);
// let mut web = tide::with_state(state.clone());
// web.with(CompressMiddleware::new());
// api::add_routes(&mut web);
app.at("/").nest(web);
// app.at("/").nest(web);
app.listen(listener).await?;
// app.listen(listener).await?;
Ok(())
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
use crate::db::{ChannelId, UserId};
use anyhow::anyhow;
use anyhow::{anyhow, Result};
use collections::{BTreeMap, HashMap, HashSet};
use rpc::{proto, ConnectionId};
use std::{collections::hash_map, path::PathBuf};
@ -99,7 +99,7 @@ impl Store {
pub fn remove_connection(
&mut self,
connection_id: ConnectionId,
) -> tide::Result<RemovedConnectionState> {
) -> Result<RemovedConnectionState> {
let connection = if let Some(connection) = self.connections.remove(&connection_id) {
connection
} else {
@ -165,7 +165,7 @@ impl Store {
}
}
pub fn user_id_for_connection(&self, connection_id: ConnectionId) -> tide::Result<UserId> {
pub fn user_id_for_connection(&self, connection_id: ConnectionId) -> Result<UserId> {
Ok(self
.connections
.get(&connection_id)
@ -258,7 +258,7 @@ impl Store {
worktree_id: u64,
connection_id: ConnectionId,
worktree: Worktree,
) -> tide::Result<()> {
) -> Result<()> {
let project = self
.projects
.get_mut(&project_id)
@ -286,7 +286,7 @@ impl Store {
&mut self,
project_id: u64,
connection_id: ConnectionId,
) -> tide::Result<Project> {
) -> Result<Project> {
match self.projects.entry(project_id) {
hash_map::Entry::Occupied(e) => {
if e.get().host_connection_id == connection_id {
@ -326,7 +326,7 @@ impl Store {
project_id: u64,
worktree_id: u64,
acting_connection_id: ConnectionId,
) -> tide::Result<(Worktree, Vec<ConnectionId>)> {
) -> Result<(Worktree, Vec<ConnectionId>)> {
let project = self
.projects
.get_mut(&project_id)
@ -363,7 +363,7 @@ impl Store {
&mut self,
project_id: u64,
connection_id: ConnectionId,
) -> tide::Result<SharedProject> {
) -> Result<SharedProject> {
if let Some(project) = self.projects.get_mut(&project_id) {
if project.host_connection_id == connection_id {
let mut share = ProjectShare::default();
@ -383,7 +383,7 @@ impl Store {
&mut self,
project_id: u64,
acting_connection_id: ConnectionId,
) -> tide::Result<UnsharedProject> {
) -> Result<UnsharedProject> {
let project = if let Some(project) = self.projects.get_mut(&project_id) {
project
} else {
@ -418,7 +418,7 @@ impl Store {
worktree_id: u64,
connection_id: ConnectionId,
summary: proto::DiagnosticSummary,
) -> tide::Result<Vec<ConnectionId>> {
) -> Result<Vec<ConnectionId>> {
let project = self
.projects
.get_mut(&project_id)
@ -443,7 +443,7 @@ impl Store {
project_id: u64,
connection_id: ConnectionId,
language_server: proto::LanguageServer,
) -> tide::Result<Vec<ConnectionId>> {
) -> Result<Vec<ConnectionId>> {
let project = self
.projects
.get_mut(&project_id)
@ -461,7 +461,7 @@ impl Store {
connection_id: ConnectionId,
user_id: UserId,
project_id: u64,
) -> tide::Result<JoinedProject> {
) -> Result<JoinedProject> {
let connection = self
.connections
.get_mut(&connection_id)
@ -498,7 +498,7 @@ impl Store {
&mut self,
connection_id: ConnectionId,
project_id: u64,
) -> tide::Result<LeftProject> {
) -> Result<LeftProject> {
let project = self
.projects
.get_mut(&project_id)
@ -533,7 +533,7 @@ impl Store {
worktree_id: u64,
removed_entries: &[u64],
updated_entries: &[proto::Entry],
) -> tide::Result<Vec<ConnectionId>> {
) -> Result<Vec<ConnectionId>> {
let project = self.write_project(project_id, connection_id)?;
let worktree = project
.share_mut()?
@ -554,13 +554,13 @@ impl Store {
&self,
project_id: u64,
acting_connection_id: ConnectionId,
) -> tide::Result<Vec<ConnectionId>> {
) -> Result<Vec<ConnectionId>> {
Ok(self
.read_project(project_id, acting_connection_id)?
.connection_ids())
}
pub fn channel_connection_ids(&self, channel_id: ChannelId) -> tide::Result<Vec<ConnectionId>> {
pub fn channel_connection_ids(&self, channel_id: ChannelId) -> Result<Vec<ConnectionId>> {
Ok(self
.channels
.get(&channel_id)
@ -573,11 +573,7 @@ impl Store {
self.projects.get(&project_id)
}
pub fn read_project(
&self,
project_id: u64,
connection_id: ConnectionId,
) -> tide::Result<&Project> {
pub fn read_project(&self, project_id: u64, connection_id: ConnectionId) -> Result<&Project> {
let project = self
.projects
.get(&project_id)
@ -600,7 +596,7 @@ impl Store {
&mut self,
project_id: u64,
connection_id: ConnectionId,
) -> tide::Result<&mut Project> {
) -> Result<&mut Project> {
let project = self
.projects
.get_mut(&project_id)
@ -755,14 +751,14 @@ impl Project {
}
}
pub fn share(&self) -> tide::Result<&ProjectShare> {
pub fn share(&self) -> Result<&ProjectShare> {
Ok(self
.share
.as_ref()
.ok_or_else(|| anyhow!("worktree is not shared"))?)
}
fn share_mut(&mut self) -> tide::Result<&mut ProjectShare> {
fn share_mut(&mut self) -> Result<&mut ProjectShare> {
Ok(self
.share
.as_mut()