feat: add client-side private key persistence and profile materialization
Store generated private key in SessionState and persist across enrollment and profile sync operations. Add materialize_profile helper that replaces placeholder tokens (__CLIENT_GENERATED_PRIVATE_KEY__ and __CLIENT_PRIVATE_KEY_REQUIRED__) with actual private key before writing profile to disk. Update enroll_device and sync_profile to materialize profile content with private key before writing.
This commit is contained in:
@@ -29,6 +29,7 @@ struct SessionState {
|
||||
refresh_token: String,
|
||||
server_url: String,
|
||||
profile_path: String,
|
||||
private_key: String,
|
||||
enrollment: EnrollmentResult,
|
||||
}
|
||||
|
||||
@@ -151,7 +152,7 @@ async fn enroll_device(
|
||||
.await
|
||||
.map_err(|err| format!("Unable to decode login response: {}", err))?;
|
||||
|
||||
let (_private_key, public_key) = generate_keypair();
|
||||
let (private_key, public_key) = generate_keypair();
|
||||
let enroll_response = client
|
||||
.post(format!("{}/api/v1/devices/enroll", payload.server_url.trim_end_matches('/')))
|
||||
.bearer_auth(&login.access_token)
|
||||
@@ -181,7 +182,8 @@ async fn enroll_device(
|
||||
.await
|
||||
.map_err(|err| format!("Unable to decode enrollment response: {}", err))?;
|
||||
|
||||
let profile_path = write_profile(&app, &enroll.profile.content)?;
|
||||
let profile_content = materialize_profile(&enroll.profile.content, &private_key);
|
||||
let profile_path = write_profile(&app, &profile_content)?;
|
||||
let result = EnrollmentResult {
|
||||
assigned_ip: enroll.peer.assigned_ip,
|
||||
resources: enroll.resources.into_iter().map(|resource| resource.value).collect(),
|
||||
@@ -197,6 +199,7 @@ async fn enroll_device(
|
||||
refresh_token: login.refresh_token,
|
||||
server_url: payload.server_url,
|
||||
profile_path: result.profile_path.clone(),
|
||||
private_key,
|
||||
enrollment: result.clone(),
|
||||
};
|
||||
|
||||
@@ -266,7 +269,8 @@ async fn sync_profile(app: AppHandle, state: State<'_, AppState>) -> Result<Enro
|
||||
.await
|
||||
.map_err(|err| format!("Unable to decode profile sync response: {}", err))?;
|
||||
|
||||
let profile_path = write_profile(&app, &enroll.profile.content)?;
|
||||
let profile_content = materialize_profile(&enroll.profile.content, &existing.private_key);
|
||||
let profile_path = write_profile(&app, &profile_content)?;
|
||||
let result = EnrollmentResult {
|
||||
assigned_ip: enroll.peer.assigned_ip,
|
||||
resources: enroll.resources.into_iter().map(|resource| resource.value).collect(),
|
||||
@@ -282,6 +286,7 @@ async fn sync_profile(app: AppHandle, state: State<'_, AppState>) -> Result<Enro
|
||||
refresh_token: existing.refresh_token,
|
||||
server_url: existing.server_url,
|
||||
profile_path: result.profile_path.clone(),
|
||||
private_key: existing.private_key,
|
||||
enrollment: result.clone(),
|
||||
};
|
||||
|
||||
@@ -330,6 +335,12 @@ fn build_fingerprint(server_url: &str, username: &str, public_key: &str) -> Stri
|
||||
format!("nexavpn:{}:{}:{}", server_url, username, public_key)
|
||||
}
|
||||
|
||||
fn materialize_profile(profile_content: &str, private_key: &str) -> String {
|
||||
profile_content
|
||||
.replace("__CLIENT_GENERATED_PRIVATE_KEY__", private_key)
|
||||
.replace("__CLIENT_PRIVATE_KEY_REQUIRED__", private_key)
|
||||
}
|
||||
|
||||
fn write_profile(app: &AppHandle, profile_content: &str) -> Result<PathBuf, String> {
|
||||
let app_dir = ensure_app_dir(app)?;
|
||||
let profile_path = app_dir.join(format!("{}.conf", PROFILE_NAME));
|
||||
|
||||
Reference in New Issue
Block a user