blob: 108e2aaeac8f842db82c18074b2c9be5552a27c0 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors
//
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed except according to
// those terms.
use argh::FromArgs;
use mock_omaha_server::{
OmahaServer, OmahaServerBuilder, PrivateKeyAndId, PrivateKeys, ResponseAndMetadata,
};
use std::collections::HashMap;
use std::net::{Ipv6Addr, SocketAddr};
use std::sync::Arc;
#[cfg(feature = "tokio")]
use tokio::sync::Mutex;
#[cfg(fasync)]
use {fuchsia_async as fasync, fuchsia_sync::Mutex};
#[derive(FromArgs)]
/// Arguments for mock-omaha-server.
struct Args {
/// A hashmap from appid to response metadata struct.
/// Example JSON argument (the minimal set of required fields per appid):
/// {
/// "appid_01": {
/// "response": "NoUpdate",
/// "check_assertion": "UpdatesEnabled",
/// "version": "0.1.2.3",
/// "codebase": "fuchsia-pkg://omaha.mock.fuchsia.com/",
/// "package_name": "update?hash=deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
/// },
/// ...
/// }
#[argh(
option,
description = "responses and metadata keyed by appid",
from_str_fn(parse_responses_by_appid),
default = "parse_responses_by_appid(EXAMPLE_RESPONSES_BY_APPID).unwrap()"
)]
responses_by_appid: HashMap<String, ResponseAndMetadata>,
#[argh(
option,
description = "private key ID",
default = "DEFAULT_PRIVATE_KEY_ID.try_into().expect(\"key parse\")"
)]
key_id: u64,
#[argh(
option,
description = "path to private key",
default = "\"mock-omaha-server/src/testing_keys/test_private_key.pem\".to_string()"
)]
key_path: String,
#[argh(option, description = "which port to serve on", default = "0")]
port: u16,
#[argh(
option,
description = "which IP address to listen on. One of '::', '::1', or anything Ipv6Addr::from_str() can interpret.",
default = "Ipv6Addr::UNSPECIFIED"
)]
listen_on: Ipv6Addr,
#[argh(
switch,
description = "if 'true', will only accept requests with CUP enabled."
)]
require_cup: bool,
}
fn parse_responses_by_appid(value: &str) -> Result<HashMap<String, ResponseAndMetadata>, String> {
serde_json::from_str(value).map_err(|e| format!("Parsing failed: {e:?}"))
}
pub const DEFAULT_PRIVATE_KEY_ID: i32 = 42;
const EXAMPLE_RESPONSES_BY_APPID: &str = r#"
{
"appid_01": {
"response": "NoUpdate",
"check_assertion": "UpdatesEnabled",
"version": "14.20230831.4.72",
"codebase": "fuchsia-pkg://omaha.mock.fuchsia.com/",
"package_name": "update?hash=deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
}
}
"#;
#[cfg_attr(fasync, fasync::run(10))]
#[cfg_attr(feature = "tokio", tokio::main)]
async fn main() -> Result<(), anyhow::Error> {
let args: Args = argh::from_env();
let (local_addr, task) = OmahaServer::start(
Arc::new(Mutex::new(
OmahaServerBuilder::default()
.responses_by_appid(args.responses_by_appid)
.private_keys(PrivateKeys {
latest: PrivateKeyAndId {
id: args.key_id,
key: std::fs::read_to_string(&args.key_path)
.unwrap_or_else(|_| {
panic!("read from key_path '{:#?}' failed", args.key_path)
})
.parse()
.expect("failed to parse key"),
},
historical: vec![],
})
.require_cup(args.require_cup)
.build()
.expect("omaha server build"),
)),
Some(SocketAddr::new(args.listen_on.into(), args.port)),
)
.await?;
println!("listening on {local_addr}");
if let Some(t) = task {
#[cfg(fasync)]
{
t.await;
Ok(())
}
#[cfg(feature = "tokio")]
{
Ok(t.await?)
}
} else {
Ok(())
}
}