Add the fetching of user JSON by github login with a token header

Nathan Sobo created

Change summary

crates/server/.env.toml   |  1 
crates/server/src/api.rs  | 43 +++++++++++++++++++++++++++++++++++++++++
crates/server/src/main.rs |  3 ++
3 files changed, 47 insertions(+)

Detailed changes

crates/server/.env.toml 🔗

@@ -5,6 +5,7 @@ HTTP_PORT = 8080
 
 DATABASE_URL = "postgres://postgres@localhost/zed"
 SESSION_SECRET = "6E1GS6IQNOLIBKWMEVWF1AFO4H78KNU8"
+API_TOKEN = "secret"
 
 # Available at https://github.com/organizations/zed-industries/settings/apps/zed-local-development
 GITHUB_APP_ID = 115633

crates/server/src/api.rs 🔗

@@ -0,0 +1,43 @@
+use crate::{AppState, Request, RequestExt as _};
+use async_trait::async_trait;
+use std::sync::Arc;
+
+pub fn add_routes(app: &mut tide::Server<Arc<AppState>>) {
+    app.at("/users/:github_login").get(get_user);
+}
+
+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"))?;
+
+    Ok(tide::Response::builder(200)
+        .body(tide::Body::from_json(&user)?)
+        .build())
+}
+
+#[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"))?;
+
+        if token == self.state().config.api_token {
+            Ok(())
+        } else {
+            Err(tide::Error::from_str(403, "invalid authorization token"))
+        }
+    }
+}

crates/server/src/main.rs 🔗

@@ -1,4 +1,5 @@
 mod admin;
+mod api;
 mod assets;
 mod auth;
 mod community;
@@ -43,6 +44,7 @@ pub struct Config {
     pub github_client_id: String,
     pub github_client_secret: String,
     pub github_private_key: String,
+    pub api_token: String,
 }
 
 pub struct AppState {
@@ -173,6 +175,7 @@ pub async fn run_server(
         .with_same_site_policy(SameSite::Lax), // Required obtain our session in /auth_callback
     );
     web.with(errors::Middleware);
+    api::add_routes(&mut web);
     home::add_routes(&mut web);
     team::add_routes(&mut web);
     releases::add_routes(&mut web);