-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract utils from main function and unit test it
Related-to: TOR-3521 Signed-off-by: Leonardo Held <[email protected]>
- Loading branch information
1 parent
d44e167
commit 1ef9c32
Showing
7 changed files
with
173 additions
and
75 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIBdTCCARygAwIBAgIUXTaOb4/pIH1jZ+RyhAZvdi41/0QwCgYIKoZIzj0EAwIw | ||
GTEXMBUGA1UEAwwOb3RhLWRldmljZXMtQ0EwIBcNMjQwODE5MTQxMzQ3WhgPMjEy | ||
NDA4MTkxNDEzNDdaMC8xLTArBgNVBAMTJDg4OGIyNTQ1LWEzMGYtNDg5Ni1hMzc3 | ||
LWI0N2M0YjcyNTM3NDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMQh0ZB30O5x | ||
Pp7k5vICJ0QOdxoubO0VtTCJX+zQ2oCmjFBatfUH5gjuNsdmCw1zf7FeQCDyYnP9 | ||
OQRoHLPBcwyjKjAoMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEF | ||
BQcDAjAKBggqhkjOPQQDAgNHADBEAiBmj6SenB1MEca664lGUkDIdsPzYAQ7G1Ml | ||
tipTcMGIpwIgPbJMmfRXiSZjLGjdmhr43cG8S3ALrcXIHDyQdVmA8lI= | ||
-----END CERTIFICATE----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
-----BEGIN EC PRIVATE KEY----- | ||
MHcCAQEEIM5yZsvOEcDQY571vHH6UJQwKPjvyoYgcgwKF4pwu6tgoAoGCCqGSM49 | ||
AwEHoUQDQgAExCHRkHfQ7nE+nuTm8gInRA53Gi5s7RW1MIlf7NDagKaMUFq19Qfm | ||
CO42x2YLDXN/sV5AIPJic/05BGgcs8FzDA== | ||
-----END EC PRIVATE KEY----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Copyright 2024 Toradex A.G. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::fs::File; | ||
use std::io::BufReader; | ||
use std::path::Path; | ||
use rustls_pemfile; | ||
use eyre::{Context, Result, OptionExt}; | ||
use x509_parser::prelude::*; | ||
use serde_json; | ||
use crate::CertificateDer; | ||
use crate::PrivateKeyDer; | ||
|
||
// blocking | ||
pub fn load_cert<P: AsRef<Path>>(filename: P) -> Result<CertificateDer<'static>> { | ||
let certfile = | ||
File::open(&filename).context(format!("opening {:?}", filename.as_ref()))?; | ||
let mut reader = BufReader::new(&certfile); | ||
let mut all_certs: Vec<CertificateDer> = rustls_pemfile::certs(&mut reader).flatten().collect(); | ||
|
||
if all_certs.len() != 1 { | ||
eyre::bail!( | ||
"invalid number of certificates in {:?}, expected 1 got {:?}", | ||
filename.as_ref(), | ||
all_certs.len() | ||
); | ||
} | ||
|
||
#[allow(clippy::unwrap_used)] // length checked | ||
Ok(all_certs.pop().unwrap()) | ||
} | ||
|
||
// blocking | ||
pub fn load_private_key<P: AsRef<Path>>(filename: P) -> Result<PrivateKeyDer<'static>> { | ||
let keyfile = | ||
File::open(&filename).context(format!("read {:?}", filename.as_ref()))?; | ||
let mut reader = BufReader::new(keyfile); | ||
|
||
loop { | ||
match rustls_pemfile::read_one(&mut reader)? { | ||
Some(rustls_pemfile::Item::Pkcs1Key(key)) => return Ok(key.into()), | ||
Some(rustls_pemfile::Item::Pkcs8Key(key)) => return Ok(key.into()), | ||
Some(rustls_pemfile::Item::Sec1Key(key)) => return Ok(key.into()), | ||
None => break, | ||
_ => {} | ||
} | ||
} | ||
|
||
eyre::bail!( | ||
"no keys found in {:?} (encrypted keys not supported)", | ||
filename.as_ref() | ||
); | ||
} | ||
|
||
pub fn read_device_id(cert: &CertificateDer) -> Result<String> { | ||
let (_, res) = X509Certificate::from_der(cert)?; | ||
|
||
let common_name = res | ||
.subject | ||
.iter_common_name() | ||
.flat_map(|c| c.as_str()) | ||
.next(); | ||
|
||
Ok(common_name | ||
.ok_or(eyre::eyre!("Could not extract uuid from certificate CN"))? | ||
.to_owned()) | ||
} | ||
|
||
pub fn parse_payload(payload: &[u8]) -> Result<(String, serde_json::Value)> { | ||
let mut payload_json: serde_json::Value = serde_json::from_slice(payload)?; | ||
|
||
let args_json = payload_json | ||
.pointer_mut("/args") | ||
.ok_or_eyre("message payload did not include `args`")? | ||
.take(); | ||
|
||
let command = payload_json | ||
.pointer("/command") | ||
.and_then(|s| s.as_str().map(|s| s.to_owned())) | ||
.ok_or_eyre("message payload did not include `command`")?; | ||
|
||
Ok((command, args_json)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright 2024 Toradex A.G. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::path::{Path}; | ||
|
||
use crate::utils::{load_cert, load_private_key, read_device_id, parse_payload}; | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
|
||
#[test] | ||
fn test_load_cert() { | ||
let cert_path = Path::new("src/test_data/client.crt"); | ||
let result = load_cert(cert_path); | ||
assert!(result.is_ok(), "Failed to load certificate: {:?}", result.err()); | ||
|
||
let cert = result.expect("Valid certificate"); | ||
assert!(cert.len() > 0, "Certificate data should not be empty"); | ||
} | ||
|
||
#[test] | ||
fn test_load_private_key() { | ||
let key_path = Path::new("src/test_data/client.key"); | ||
let result = load_private_key(key_path); | ||
assert!(result.is_ok(), "Failed to load private key: {:?}", result.err()); | ||
} | ||
|
||
#[test] | ||
fn test_read_device_id() { | ||
let cert_path = Path::new("src/test_data/client.crt"); | ||
let cert = load_cert(cert_path).expect("Failed to load cert"); | ||
let result = read_device_id(&cert); | ||
assert!(result.is_ok(), "Failed to read device id: {:?}", result.err()); | ||
|
||
let device_id = result.expect("Valid device ID"); | ||
assert!(!device_id.is_empty(), "Device ID should not be empty"); | ||
} | ||
|
||
#[test] | ||
fn test_parse_payload() { | ||
let payload = br#"{"command": "test", "args": {"key": "value"}}"#; | ||
let result = parse_payload(payload); | ||
assert!(result.is_ok(), "Failed to parse payload: {:?}", result.err()); | ||
|
||
let (command, args) = result.expect("Valid command and args"); | ||
assert_eq!(command, "test"); | ||
assert_eq!(args["key"], "value"); | ||
} | ||
|
||
#[test] | ||
fn test_parse_payload_missing_args() { | ||
let payload = br#"{"command": "test"}"#; | ||
let result = parse_payload(payload); | ||
assert!(result.is_err(), "Expected error for missing `args`, got: {:?}", result); | ||
} | ||
|
||
#[test] | ||
fn test_parse_payload_missing_command() { | ||
let payload = br#"{"args": {"key": "value"}}"#; | ||
let result = parse_payload(payload); | ||
assert!(result.is_err(), "Expected error for missing `command`, got: {:?}", result); | ||
} | ||
} |