feat: add auth_token to user table
parent
2714b88878
commit
0a6a68db57
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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`)
|
||||||
);
|
);
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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?;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue