feat: add auth_token to user table

support-auth-token
Meng Zhang 2023-12-08 13:46:57 +08:00
parent 2714b88878
commit 0a6a68db57
3 changed files with 29 additions and 7 deletions

View File

@ -8,17 +8,19 @@ use juniper::{FieldError, GraphQLObject, IntoFieldError, ScalarValue};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
use tracing::{error, warn};
use uuid::Uuid; use uuid::Uuid;
use validator::ValidationErrors; use validator::ValidationErrors;
use super::from_validation_errors; use super::from_validation_errors;
lazy_static! { lazy_static! {
static ref JWT_TOKEN_SECRET: String = jwt_token_secret();
static ref JWT_ENCODING_KEY: jwt::EncodingKey = jwt::EncodingKey::from_secret( static ref JWT_ENCODING_KEY: jwt::EncodingKey = jwt::EncodingKey::from_secret(
jwt_token_secret().as_bytes() JWT_TOKEN_SECRET.as_bytes()
); );
static ref JWT_DECODING_KEY: jwt::DecodingKey = jwt::DecodingKey::from_secret( static ref JWT_DECODING_KEY: jwt::DecodingKey = jwt::DecodingKey::from_secret(
jwt_token_secret().as_bytes() JWT_TOKEN_SECRET.as_bytes()
); );
static ref JWT_DEFAULT_EXP: u64 = 30 * 60; // 30 minutes static ref JWT_DEFAULT_EXP: u64 = 30 * 60; // 30 minutes
} }
@ -36,7 +38,19 @@ pub fn validate_jwt(token: &str) -> jwt::errors::Result<Claims> {
} }
fn jwt_token_secret() -> String { fn jwt_token_secret() -> String {
std::env::var("TABBY_WEBSERVER_JWT_TOKEN_SECRET").unwrap_or("default_secret".to_string()) let jwt_secret = match std::env::var("TABBY_WEBSERVER_JWT_TOKEN_SECRET") {
Ok(x) => x,
Err(_) => {
warn!(r"TABBY_WEBSERVER_JWT_TOKEN_SECRET is not set. Tabby generates a one-time (non-persisted) JWT token solely for testing purposes.");
Uuid::new_v4().to_string()
}
};
if uuid::Uuid::parse_str(&jwt_secret).is_err() {
warn!("JWT token secret needs to be in standard uuid format to ensure its security, you might generate one at https://www.uuidgenerator.net");
}
jwt_secret
} }
pub fn generate_refresh_token() -> String { pub fn generate_refresh_token() -> String {

View File

@ -36,7 +36,10 @@ lazy_static! {
is_admin BOOLEAN NOT NULL DEFAULT 0, is_admin BOOLEAN NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT (DATETIME('now')), created_at TIMESTAMP DEFAULT (DATETIME('now')),
updated_at TIMESTAMP DEFAULT (DATETIME('now')), updated_at TIMESTAMP DEFAULT (DATETIME('now')),
CONSTRAINT `idx_email` UNIQUE (`email`) auth_token VARCHAR(128) NOT NULL,
CONSTRAINT `idx_email` UNIQUE (`email`)
CONSTRAINT `idx_auth_token` UNIQUE (`auth_token`)
); );
"# "#
) )

View File

@ -3,6 +3,7 @@
use anyhow::Result; use anyhow::Result;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use rusqlite::{params, OptionalExtension, Row}; use rusqlite::{params, OptionalExtension, Row};
use uuid::Uuid;
use super::DbConn; use super::DbConn;
@ -15,11 +16,14 @@ pub struct User {
pub email: String, pub email: String,
pub password_encrypted: String, pub password_encrypted: String,
pub is_admin: bool, pub is_admin: bool,
/// To authenticate IDE extensions / plugins to access code completion / chat api endpoints.
auth_token: String,
} }
impl User { impl User {
fn select(clause: &str) -> String { fn select(clause: &str) -> String {
r#"SELECT id, email, password_encrypted, is_admin, created_at, updated_at FROM users WHERE "# r#"SELECT id, email, password_encrypted, is_admin, created_at, updated_at, auth_token FROM users WHERE "#
.to_owned() .to_owned()
+ clause + clause
} }
@ -32,6 +36,7 @@ impl User {
is_admin: row.get(3)?, is_admin: row.get(3)?,
created_at: row.get(4)?, created_at: row.get(4)?,
updated_at: row.get(5)?, updated_at: row.get(5)?,
auth_token: row.get(6)?,
}) })
} }
} }
@ -47,9 +52,9 @@ impl DbConn {
.conn .conn
.call(move |c| { .call(move |c| {
let mut stmt = c.prepare( let mut stmt = c.prepare(
r#"INSERT INTO users (email, password_encrypted, is_admin) VALUES (?, ?, ?)"#, r#"INSERT INTO users (email, password_encrypted, is_admin, auth_token) VALUES (?, ?, ?, ?)"#,
)?; )?;
let id = stmt.insert((email, password_encrypted, is_admin))?; let id = stmt.insert((email, password_encrypted, is_admin, Uuid::new_v4().to_string()))?;
Ok(id) Ok(id)
}) })
.await?; .await?;