Allow disabling automatic creation of clients

This may be useful in multi-user deployment scenarios where some
external administrative tools are used to create new clients.
This commit is contained in:
Dustin J. Mitchell
2025-07-10 21:49:57 -04:00
parent 4de5c9a345
commit 3a794341ce
8 changed files with 117 additions and 26 deletions

View File

@ -76,11 +76,11 @@ mod test {
txn.commit()?;
}
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-snapshot/{}", version_id);
let uri = format!("/v1/client/add-snapshot/{version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.insert_header(("Content-Type", "application/vnd.taskchampion.snapshot"))
@ -119,12 +119,12 @@ mod test {
txn.commit().unwrap();
}
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
// add a snapshot for a nonexistent version
let uri = format!("/v1/client/add-snapshot/{}", version_id);
let uri = format!("/v1/client/add-snapshot/{version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header(("Content-Type", "application/vnd.taskchampion.snapshot"))
@ -149,11 +149,11 @@ mod test {
let client_id = Uuid::new_v4();
let version_id = Uuid::new_v4();
let storage = InMemoryStorage::new();
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-snapshot/{}", version_id);
let uri = format!("/v1/client/add-snapshot/{version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header(("Content-Type", "not/correct"))
@ -169,11 +169,11 @@ mod test {
let client_id = Uuid::new_v4();
let version_id = Uuid::new_v4();
let storage = InMemoryStorage::new();
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-snapshot/{}", version_id);
let uri = format!("/v1/client/add-snapshot/{version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header((

View File

@ -80,7 +80,7 @@ pub(crate) async fn service(
rb.append_header((PARENT_VERSION_ID_HEADER, parent_version_id.to_string()));
Ok(rb.finish())
}
Err(ServerError::NoSuchClient) => {
Err(ServerError::NoSuchClient) if server_state.create_clients => {
// Create a new client and repeat the `add_version` call.
let mut txn = server_state
.server
@ -118,11 +118,11 @@ mod test {
txn.commit().unwrap();
}
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-version/{}", parent_version_id);
let uri = format!("/v1/client/add-version/{parent_version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header((
@ -152,11 +152,11 @@ mod test {
let client_id = Uuid::new_v4();
let version_id = Uuid::new_v4();
let parent_version_id = Uuid::new_v4();
let server = WebServer::new(Default::default(), None, InMemoryStorage::new());
let server = WebServer::new(Default::default(), None, true, InMemoryStorage::new());
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-version/{}", parent_version_id);
let uri = format!("/v1/client/add-version/{parent_version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header((
@ -190,6 +190,34 @@ mod test {
}
}
#[actix_rt::test]
async fn test_auto_add_client_disabled() {
let client_id = Uuid::new_v4();
let parent_version_id = Uuid::new_v4();
let server = WebServer::new(
Default::default(),
None,
/*create_clients=*/ false,
InMemoryStorage::new(),
);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-version/{parent_version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header((
"Content-Type",
"application/vnd.taskchampion.history-segment",
))
.append_header((CLIENT_ID_HEADER, client_id.to_string()))
.set_payload(b"abcd".to_vec())
.to_request();
let resp = test::call_service(&app, req).await;
// Client is not added, and returns 404.
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
#[actix_rt::test]
async fn test_conflict() {
let client_id = Uuid::new_v4();
@ -204,11 +232,11 @@ mod test {
txn.commit().unwrap();
}
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-version/{}", parent_version_id);
let uri = format!("/v1/client/add-version/{parent_version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header((
@ -232,11 +260,11 @@ mod test {
let client_id = Uuid::new_v4();
let parent_version_id = Uuid::new_v4();
let storage = InMemoryStorage::new();
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-version/{}", parent_version_id);
let uri = format!("/v1/client/add-version/{parent_version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header(("Content-Type", "not/correct"))
@ -252,11 +280,11 @@ mod test {
let client_id = Uuid::new_v4();
let parent_version_id = Uuid::new_v4();
let storage = InMemoryStorage::new();
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
let uri = format!("/v1/client/add-version/{}", parent_version_id);
let uri = format!("/v1/client/add-version/{parent_version_id}");
let req = test::TestRequest::post()
.uri(&uri)
.append_header((

View File

@ -71,7 +71,7 @@ mod test {
txn.commit().unwrap();
}
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
@ -105,7 +105,7 @@ mod test {
let client_id = Uuid::new_v4();
let parent_version_id = Uuid::new_v4();
let storage = InMemoryStorage::new();
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
@ -134,7 +134,7 @@ mod test {
.unwrap();
txn.commit().unwrap();
}
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;

View File

@ -53,7 +53,7 @@ mod test {
txn.commit().unwrap();
}
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;
@ -89,7 +89,7 @@ mod test {
txn.commit().unwrap();
}
let server = WebServer::new(Default::default(), None, storage);
let server = WebServer::new(Default::default(), None, true, storage);
let app = App::new().configure(|sc| server.config(sc));
let app = test::init_service(app).await;

View File

@ -32,6 +32,7 @@ pub(crate) const SNAPSHOT_REQUEST_HEADER: &str = "X-Snapshot-Request";
pub(crate) struct ServerState {
pub(crate) server: Server,
pub(crate) client_id_allowlist: Option<HashSet<Uuid>>,
pub(crate) create_clients: bool,
}
impl ServerState {
@ -87,6 +88,7 @@ mod test {
let state = ServerState {
server: Server::new(Default::default(), InMemoryStorage::new()),
client_id_allowlist: None,
create_clients: true,
};
let req = actix_web::test::TestRequest::default()
.insert_header((CLIENT_ID_HEADER, client_id.to_string()))
@ -101,6 +103,7 @@ mod test {
let state = ServerState {
server: Server::new(Default::default(), InMemoryStorage::new()),
client_id_allowlist: Some([client_id_ok].into()),
create_clients: true,
};
let req = actix_web::test::TestRequest::default()
.insert_header((CLIENT_ID_HEADER, client_id_ok.to_string()))