Skip to content

Commit

Permalink
feat(webserver): Use hash IDs rather than numeric row IDs in external…
Browse files Browse the repository at this point in the history
… API (TabbyML#1382)

* feat(webserver): Use hash IDs rather than numeric row IDs in external API

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* Fix unit test, apply suggested changes

* [autofix.ci] apply automated fixes

* Revert lib.rs

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
boxbeam and autofix-ci[bot] authored Feb 5, 2024
1 parent eb90722 commit 61ab457
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 16 deletions.
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions ee/tabby-db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ prod-db = []
[dependencies]
anyhow.workspace = true
chrono = { workspace = true, features = ["serde"] }
hash-ids = "0.2.1"
lazy_static.workspace = true
sqlx = { version = "0.7.3", features = ["sqlite", "chrono", "runtime-tokio"] }
tabby-common = { path = "../../crates/tabby-common" }
thiserror.workspace = true
tokio = { workspace = true, features = ["fs"] }
uuid.workspace = true

Expand Down
22 changes: 22 additions & 0 deletions ee/tabby-db/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub use email_setting::EmailSettingDAO;
pub use github_oauth_credential::GithubOAuthCredentialDAO;
pub use google_oauth_credential::GoogleOAuthCredentialDAO;
use hash_ids::HashIds;
pub use invitations::InvitationDAO;
pub use job_runs::JobRunDAO;
pub use repositories::RepositoryDAO;
Expand All @@ -18,14 +19,35 @@ mod repositories;
mod users;

use anyhow::Result;
use lazy_static::lazy_static;
use sqlx::sqlite::SqliteConnectOptions;

lazy_static! {
static ref HASHER: HashIds = HashIds::builder().with_salt("tabby-id-serializer").finish();
}

#[derive(thiserror::Error, Debug)]
#[error("Invalid ID")]
pub struct InvalidIDError;

#[derive(Clone)]
pub struct DbConn {
pool: Pool<Sqlite>,
}

impl DbConn {
pub fn to_id(rowid: i32) -> String {
HASHER.encode(&[rowid as u64])
}

pub fn to_rowid(id: &str) -> Result<i32, InvalidIDError> {
HASHER
.decode(id)
.first()
.map(|i| *i as i32)
.ok_or(InvalidIDError)
}

#[cfg(any(test, feature = "testutils"))]
pub async fn new_in_memory() -> Result<Self> {
use std::str::FromStr;
Expand Down
13 changes: 7 additions & 6 deletions ee/tabby-webserver/src/schema/dao.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use juniper::ID;
use tabby_db::{
EmailSettingDAO, GithubOAuthCredentialDAO, GoogleOAuthCredentialDAO, InvitationDAO, JobRunDAO,
RepositoryDAO, UserDAO,
DbConn, EmailSettingDAO, GithubOAuthCredentialDAO, GoogleOAuthCredentialDAO, InvitationDAO,
JobRunDAO, RepositoryDAO, UserDAO,
};

use super::{email::EmailSetting, repository::Repository};
Expand All @@ -13,7 +14,7 @@ use crate::schema::{
impl From<InvitationDAO> for auth::Invitation {
fn from(val: InvitationDAO) -> Self {
Self {
id: juniper::ID::new(val.id.to_string()),
id: ID::new(DbConn::to_id(val.id)),
email: val.email,
code: val.code,
created_at: val.created_at,
Expand All @@ -24,7 +25,7 @@ impl From<InvitationDAO> for auth::Invitation {
impl From<JobRunDAO> for job::JobRun {
fn from(run: JobRunDAO) -> Self {
Self {
id: juniper::ID::new(run.id.to_string()),
id: ID::new(DbConn::to_id(run.id)),
job_name: run.job_name,
start_time: run.start_time,
finish_time: run.finish_time,
Expand All @@ -38,7 +39,7 @@ impl From<JobRunDAO> for job::JobRun {
impl From<UserDAO> for auth::User {
fn from(val: UserDAO) -> Self {
auth::User {
id: juniper::ID::new(val.id.to_string()),
id: ID::new(DbConn::to_id(val.id)),
email: val.email,
is_admin: val.is_admin,
auth_token: val.auth_token,
Expand Down Expand Up @@ -77,7 +78,7 @@ impl From<GoogleOAuthCredentialDAO> for OAuthCredential {
impl From<RepositoryDAO> for Repository {
fn from(value: RepositoryDAO) -> Self {
Repository {
id: juniper::ID::new(value.id.to_string()),
id: ID::new(DbConn::to_id(value.id)),
name: value.name,
git_url: value.git_url,
}
Expand Down
9 changes: 5 additions & 4 deletions ee/tabby-webserver/src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub mod job;
pub mod repository;
pub mod worker;

use std::{num::ParseIntError, sync::Arc};
use std::sync::Arc;

use auth::{
validate_jwt, AuthenticationService, Invitation, RefreshTokenError, RefreshTokenResponse,
Expand All @@ -21,6 +21,7 @@ use juniper_axum::{
FromAuth,
};
use tabby_common::api::{code::CodeSearch, event::RawEventLogger};
use tabby_db::{DbConn, InvalidIDError};
use tracing::{error, warn};
use validator::ValidationErrors;
use worker::{Worker, WorkerService};
Expand Down Expand Up @@ -67,7 +68,7 @@ pub enum CoreError {
Other(#[from] anyhow::Error),

#[error("Malformed ID input")]
InvalidIDError(#[from] ParseIntError),
InvalidID(#[from] InvalidIDError),
}

impl<S: ScalarValue> IntoFieldError<S> for CoreError {
Expand Down Expand Up @@ -304,7 +305,7 @@ impl Mutation {
async fn update_user_active(ctx: &Context, id: ID, active: bool) -> Result<bool> {
ctx.locator
.auth()
.update_user_active(id.parse()?, active)
.update_user_active(DbConn::to_rowid(&id)?, active)
.await?;
Ok(true)
}
Expand Down Expand Up @@ -358,7 +359,7 @@ impl Mutation {
"Failed to send invitation email, please check your SMTP settings are correct: {e}"
);
}
Ok(ID::new(invitation.id.to_string()))
Ok(ID::new(DbConn::to_id(invitation.id)))
}

async fn create_repository(
Expand Down
6 changes: 3 additions & 3 deletions ee/tabby-webserver/src/service/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ impl AuthenticationService for DbConn {
}

async fn delete_invitation(&self, id: ID) -> Result<ID> {
let id = id.parse::<i32>()?;
Ok(ID::new(self.delete_invitation(id).await?.to_string()))
let id = DbConn::to_rowid(&id)?;
Ok(ID::new(DbConn::to_id(self.delete_invitation(id).await?)))
}

async fn reset_user_auth_token(&self, email: &str) -> Result<()> {
Expand Down Expand Up @@ -569,7 +569,7 @@ mod tests {

// Used invitation should have been deleted, following delete attempt should fail.
assert!(conn
.delete_invitation(invitation.id.parse::<i32>().unwrap())
.delete_invitation(DbConn::to_rowid(&invitation.id).unwrap())
.await
.is_err());
}
Expand Down
6 changes: 3 additions & 3 deletions ee/tabby-webserver/src/service/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ impl RepositoryService for DbConn {
Ok(self
.create_repository(input.name, input.git_url)
.await
.map(|i| ID::new(i.to_string()))?)
.map(|id| ID::new(DbConn::to_id(id)))?)
}

async fn delete_repository(&self, id: ID) -> Result<bool> {
self.delete_repository(id.parse()?).await
self.delete_repository(DbConn::to_rowid(&id)?).await
}

async fn update_repository(&self, id: ID, name: String, git_url: String) -> Result<bool> {
self.update_repository(id.parse()?, name, git_url)
self.update_repository(DbConn::to_rowid(&id)?, name, git_url)
.await
.map(|_| true)
}
Expand Down

0 comments on commit 61ab457

Please sign in to comment.