Start to build sync route
This commit is contained in:
@ -1,11 +1,14 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::crypto::pki;
|
||||
use crate::devices::device::{DeviceId, DeviceInfo};
|
||||
use crate::energy::energy_actor;
|
||||
use crate::server::custom_error::HttpResult;
|
||||
use crate::server::WebEnergyActor;
|
||||
use actix_web::{web, HttpResponse};
|
||||
use jsonwebtoken::{Algorithm, DecodingKey, Validation};
|
||||
use openssl::nid::Nid;
|
||||
use openssl::x509::X509Req;
|
||||
use openssl::x509::{X509Req, X509};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct EnrollRequest {
|
||||
@ -124,3 +127,81 @@ pub async fn get_certificate(query: web::Query<ReqWithDevID>, actor: WebEnergyAc
|
||||
.content_type("application/x-pem-file")
|
||||
.body(cert))
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct SyncRequest {
|
||||
payload: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
struct Claims {
|
||||
info: DeviceInfo,
|
||||
}
|
||||
|
||||
/// Synchronize device
|
||||
pub async fn sync_device(body: web::Json<SyncRequest>, actor: WebEnergyActor) -> HttpResult {
|
||||
// First, we need to extract device kid from query
|
||||
let Ok(jwt_header) = jsonwebtoken::decode_header(&body.payload) else {
|
||||
log::error!("Failed to decode JWT header!");
|
||||
return Ok(HttpResponse::BadRequest().json("Failed to decode JWT header!"));
|
||||
};
|
||||
|
||||
let Some(kid) = jwt_header.kid else {
|
||||
log::error!("Missing KID in JWT!");
|
||||
return Ok(HttpResponse::BadRequest().json("Missing KID in JWT!"));
|
||||
};
|
||||
|
||||
// Fetch device information
|
||||
let Some(device) = actor
|
||||
.send(energy_actor::GetSingleDevice(DeviceId(kid)))
|
||||
.await?
|
||||
else {
|
||||
log::error!("Sent a JWT for a device which does not exists!");
|
||||
return Ok(HttpResponse::NotFound().json("Sent a JWT for a device which does not exists!"));
|
||||
};
|
||||
|
||||
if !device.validated {
|
||||
log::error!("Sent a JWT for a device which is not validated!");
|
||||
return Ok(HttpResponse::PreconditionFailed()
|
||||
.json("Sent a JWT for a device which is not validated!"));
|
||||
}
|
||||
|
||||
// Check certificate revocation status
|
||||
let cert_bytes = std::fs::read(AppConfig::get().device_cert_path(&device.id))?;
|
||||
let certificate = X509::from_pem(&cert_bytes)?;
|
||||
|
||||
if pki::CertData::load_devices_ca()?.is_revoked(&certificate)? {
|
||||
log::error!("Sent a JWT using a revoked certificate!");
|
||||
return Ok(
|
||||
HttpResponse::PreconditionFailed().json("Sent a JWT using a revoked certificate!")
|
||||
);
|
||||
}
|
||||
|
||||
let (key, alg) = match DecodingKey::from_ec_pem(&cert_bytes) {
|
||||
Ok(key) => (key, Algorithm::ES256),
|
||||
Err(e) => {
|
||||
log::warn!("Failed to decode certificate as EC certificate {e}, trying RSA...");
|
||||
(
|
||||
DecodingKey::from_rsa_pem(&cert_bytes).expect("Failed to decode RSA certificate"),
|
||||
Algorithm::RS256,
|
||||
)
|
||||
}
|
||||
};
|
||||
let mut validation = Validation::new(alg);
|
||||
validation.validate_exp = false;
|
||||
validation.required_spec_claims = HashSet::default();
|
||||
|
||||
let c = match jsonwebtoken::decode::<Claims>(&body.payload, &key, &validation) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
log::error!("Failed to validate JWT! {e}");
|
||||
return Ok(HttpResponse::PreconditionFailed().json("Failed to validate JWT!"));
|
||||
}
|
||||
};
|
||||
|
||||
let res = actor
|
||||
.send(energy_actor::SynchronizeDevice(device.id, c.claims.info))
|
||||
.await??;
|
||||
|
||||
Ok(HttpResponse::Ok().json(res))
|
||||
}
|
||||
|
@ -194,6 +194,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
||||
"/devices_api/mgmt/get_certificate",
|
||||
web::get().to(mgmt_controller::get_certificate),
|
||||
)
|
||||
.route(
|
||||
"/devices_api/mgmt/sync",
|
||||
web::post().to(mgmt_controller::sync_device),
|
||||
)
|
||||
// Web app
|
||||
.route("/", web::get().to(web_app_controller::root_index))
|
||||
.route(
|
||||
|
Reference in New Issue
Block a user