misc fixes

This commit is contained in:
Aiden McClelland
2021-09-01 14:47:49 -06:00
committed by Aiden McClelland
parent be5952cb67
commit e9faf1f74d
9 changed files with 141 additions and 32 deletions

View File

@@ -3,7 +3,7 @@ CREATE TABLE IF NOT EXISTS tor
(
package TEXT NOT NULL,
interface TEXT NOT NULL,
key BLOB NOT NULL,
key BLOB NOT NULL CHECK (length(key) = 64),
PRIMARY KEY (package, interface)
);
CREATE TABLE IF NOT EXISTS session
@@ -19,7 +19,7 @@ CREATE TABLE IF NOT EXISTS account
(
id INTEGER PRIMARY KEY CHECK (id = 0),
password TEXT NOT NULL,
tor_key BLOB NOT NULL
tor_key BLOB NOT NULL CHECK (length(tor_key) = 64)
);
CREATE TABLE IF NOT EXISTS ssh_keys
(

View File

@@ -10,7 +10,7 @@ use serde_json::Value;
use crate::id::{Id, ImageId};
use crate::s9pk::manifest::{PackageId, SYSTEM_PACKAGE_ID};
use crate::util::{IoFormat, Version};
use crate::volume::{Volume, VolumeId, Volumes};
use crate::volume::{VolumeId, Volumes};
use crate::{Error, ResultExt, HOST_IP};
pub const NET_TLD: &'static str = "embassy";
@@ -195,7 +195,7 @@ impl DockerAction {
let mut res = Vec::with_capacity(
(2 * self.mounts.len()) // --mount <MOUNT_ARG>
+ (2 * self.shm_size_mb.is_some() as usize) // --shm-size <SHM_SIZE>
+ 3 // --entrypoint <ENTRYPOINT> <IMAGE>
+ 4 // --log-driver=journald --entrypoint <ENTRYPOINT> <IMAGE>
+ self.args.len(), // [ARG...]
);
for (volume_id, dst) in &self.mounts {
@@ -227,6 +227,7 @@ impl DockerAction {
res.push(OsString::from(Self::container_name(pkg_id, None)).into());
res.push(OsStr::new(&self.entrypoint).into());
} else {
res.push(OsStr::new("--log-driver=journald").into());
res.push(OsStr::new("--entrypoint").into());
res.push(OsStr::new(&self.entrypoint).into());
if self.system {

View File

@@ -117,7 +117,7 @@ pub async fn login(
res.headers.insert(
"set-cookie",
HeaderValue::from_str(&format!(
"session={}; HttpOnly; SameSite=Strict; Expires=Fri, 31 Dec 9999 23:59:59 GMT;",
"session={}; SameSite=Strict; Expires=Fri, 31 Dec 9999 23:59:59 GMT;",
token
))
.with_kind(crate::ErrorKind::Unknown)?, // Should be impossible, but don't want to panic

View File

@@ -19,7 +19,7 @@ pub async fn tor_health_check_daemon(tor_controller: &TorController) {
json!({
"jsonrpc": "2.0",
"method": "echo",
"params": [{ "message": "Follow the orange rabbit" }],
"params": { "message": "Follow the orange rabbit" },
})
.to_string()
.into_bytes(),
@@ -28,7 +28,7 @@ pub async fn tor_health_check_daemon(tor_controller: &TorController) {
.await;
match result {
// if success, do nothing
Ok(response) => {}
Ok(_) => {}
// if failure, disconnect tor control port, and restart tor controller
Err(e) => {
log::error!("Unable to reach self over tor: {}", e);

View File

@@ -4,7 +4,7 @@ pub mod util;
use std::future::Future;
use std::sync::Arc;
use futures::{SinkExt, StreamExt};
use futures::{FutureExt, SinkExt, StreamExt};
use patch_db::json_ptr::JsonPointer;
use patch_db::{Dump, Revision};
use rpc_toolkit::command;
@@ -34,7 +34,17 @@ async fn ws_handler<
.await
.with_kind(crate::ErrorKind::Network)?
.with_kind(crate::ErrorKind::Unknown)?;
stream.next().await;
loop {
if let Some(Message::Text(_)) = stream
.next()
.await
.transpose()
.with_kind(crate::ErrorKind::Network)?
{
// TODO: check auth
break;
}
}
stream
.send(Message::Text(
rpc_toolkit::serde_json::to_string(&dump).with_kind(crate::ErrorKind::Serialization)?,
@@ -43,20 +53,44 @@ async fn ws_handler<
.with_kind(crate::ErrorKind::Network)?;
loop {
let rev = sub.recv().await.with_kind(crate::ErrorKind::Database)?;
stream
.send(Message::Text(
rpc_toolkit::serde_json::to_string(&rev)
.with_kind(crate::ErrorKind::Serialization)?,
))
.await
.with_kind(crate::ErrorKind::Network)?;
futures::select! {
new_rev = sub.recv().fuse() => {
let rev = new_rev.with_kind(crate::ErrorKind::Database)?;
stream
.send(Message::Text(
rpc_toolkit::serde_json::to_string(&rev)
.with_kind(crate::ErrorKind::Serialization)?,
))
.await
.with_kind(crate::ErrorKind::Network)?;
}
message = stream.next().fuse() => {
match message.transpose().with_kind(crate::ErrorKind::Network)? {
Some(Message::Ping(a)) => {
stream
.send(Message::Pong(a))
.await
.with_kind(crate::ErrorKind::Network)?;
}
Some(Message::Close(frame)) => {
if let Some(reason) = frame.as_ref() {
log::info!("Closing WebSocket: Reason: {} {}", reason.code, reason.reason);
}
stream
.send(Message::Close(frame))
.await
.with_kind(crate::ErrorKind::Network)?;
return Ok(())
}
_ => (),
}
}
}
}
}
pub async fn subscribe(ctx: RpcContext, req: Request<Body>) -> Result<Response<Body>, Error> {
let (parts, body) = req.into_parts();
// is_authed(&ctx, &parts).await?;
let req = Request::from_parts(parts, body);
let (res, ws_fut) = hyper_ws_listener::create_ws(req).with_kind(crate::ErrorKind::Network)?;
if let Some(ws_fut) = ws_fut {

View File

@@ -59,11 +59,12 @@ pub fn echo(#[arg] message: String) -> Result<String, RpcError> {
#[command(subcommands(
version::git_info,
echo,
developer::init,
s9pk::pack,
s9pk::verify,
developer::init,
inspect::inspect,
package,
net::net,
auth::auth,
db::db,
))]

View File

@@ -1,5 +1,6 @@
use std::net::{Ipv4Addr, SocketAddr};
use rpc_toolkit::command;
use torut::onion::TorSecretKeyV3;
use self::interface::{Interface, InterfaceId};
@@ -16,6 +17,11 @@ pub mod mdns;
pub mod tor;
pub mod wifi;
#[command(subcommands(tor::tor))]
pub fn net() -> Result<(), Error> {
Ok(())
}
pub struct NetController {
pub tor: TorController,
#[cfg(feature = "avahi")]

View File

@@ -3,8 +3,10 @@ use std::net::{Ipv4Addr, SocketAddr};
use std::time::Duration;
use anyhow::anyhow;
use clap::ArgMatches;
use futures::future::BoxFuture;
use futures::FutureExt;
use rpc_toolkit::command;
use sqlx::{Executor, Sqlite};
use tokio::net::TcpStream;
use tokio::sync::Mutex;
@@ -12,7 +14,9 @@ use torut::control::{AsyncEvent, AuthenticatedConn, ConnError};
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
use super::interface::{InterfaceId, TorConfig};
use crate::context::RpcContext;
use crate::s9pk::manifest::PackageId;
use crate::util::{display_serializable, IoFormat};
use crate::{Error, ErrorKind, ResultExt as _};
#[test]
@@ -20,6 +24,36 @@ fn random_key() {
println!("'0x{}'", hex::encode(TorSecretKeyV3::generate().as_bytes()));
}
#[command(subcommands(list_services))]
pub fn tor() -> Result<(), Error> {
Ok(())
}
fn display_services(services: Vec<OnionAddressV3>, matches: &ArgMatches<'_>) {
use prettytable::*;
if matches.is_present("format") {
return display_serializable(services, matches);
}
let mut table = Table::new();
for service in services {
let row = row![&service.to_string()];
table.add_row(row);
}
table.print_tty(false);
}
#[command(rename = "list-services", display(display_services))]
pub async fn list_services(
#[context] ctx: RpcContext,
#[allow(unused_variables)]
#[arg(long = "format")]
format: Option<IoFormat>,
) -> Result<Vec<OnionAddressV3>, Error> {
ctx.net_controller.tor.list_services().await
}
pub async fn os_key<Ex>(secrets: &mut Ex) -> Result<TorSecretKeyV3, Error>
where
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
@@ -79,6 +113,10 @@ impl TorController {
pub async fn embassyd_onion(&self) -> OnionAddressV3 {
self.0.lock().await.embassyd_onion()
}
pub async fn list_services(&self) -> Result<Vec<OnionAddressV3>, Error> {
self.0.lock().await.list_services().await
}
}
type AuthenticatedConnection = AuthenticatedConn<
@@ -154,10 +192,7 @@ impl TorControllerInner {
self.connection
.as_mut()
.ok_or_else(|| {
Error::new(
anyhow!("Missing Tor Control Connection"),
ErrorKind::Unknown,
)
Error::new(anyhow!("Missing Tor Control Connection"), ErrorKind::Tor)
})?
.del_onion(
&key.public()
@@ -200,9 +235,13 @@ impl TorControllerInner {
}
async fn add_embassyd_onion(&mut self) -> Result<(), Error> {
log::info!(
"Registering Main Tor Service: {}",
self.embassyd_tor_key.public().get_onion_address()
);
self.connection
.as_mut()
.expect("Tor Connection is None")
.ok_or_else(|| Error::new(anyhow!("Missing Tor Control Connection"), ErrorKind::Tor))?
.add_onion_v3(
&self.embassyd_tor_key,
false,
@@ -212,6 +251,10 @@ impl TorControllerInner {
&mut std::iter::once(&(self.embassyd_addr.port(), self.embassyd_addr)),
)
.await?;
log::info!(
"Registered Main Tor Service: {}",
self.embassyd_tor_key.public().get_onion_address()
);
Ok(())
}
@@ -223,6 +266,7 @@ impl TorControllerInner {
let uptime = c.get_info("uptime").await?.parse::<u64>()?;
// we never want to restart the tor daemon if it hasn't been up for at least a half hour
if uptime < 1800 {
self.connection = Some(c); // put it back
return Ok(false);
}
// when connection closes below, tor daemon is restarted
@@ -251,11 +295,11 @@ impl TorControllerInner {
let uptime_new = new_connection.get_info("uptime").await?.parse::<u64>()?;
// if the new uptime exceeds the one we got at the beginning, it's the same tor daemon, do not proceed
match uptime {
Some(uptime) if uptime_new < uptime => {
Some(uptime) if uptime_new > uptime => (),
_ => {
new_connection.set_async_event_handler(Some(event_handler));
break;
}
_ => (),
}
}
Err(e) => {
@@ -289,6 +333,17 @@ impl TorControllerInner {
fn embassyd_onion(&self) -> OnionAddressV3 {
self.embassyd_tor_key.public().get_onion_address()
}
async fn list_services(&mut self) -> Result<Vec<OnionAddressV3>, Error> {
self.connection
.as_mut()
.ok_or_else(|| Error::new(anyhow!("Missing Tor Control Connection"), ErrorKind::Tor))?
.get_info("onions/current")
.await?
.lines()
.map(|l| l.trim().parse().with_kind(ErrorKind::Tor))
.collect()
}
}
#[tokio::test]

24
ui/package-lock.json generated
View File

@@ -16820,7 +16820,9 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
"dev": true,
"requires": {}
"requires": {
"ajv": "^8.0.0"
}
},
"core-js": {
"version": "3.16.0",
@@ -16898,7 +16900,9 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
"dev": true,
"requires": {}
"requires": {
"ajv": "^8.0.0"
}
},
"json-schema-traverse": {
"version": "1.0.0",
@@ -16942,7 +16946,9 @@
"integrity": "sha512-Brah4Uo5/U8v76c6euTwtjVFFaVishwnJrQBYpev1JRh4vjA1F4HY3UzQez41YUCszUCXKagG8v6eVRBHV1gkw==",
"dev": true,
"peer": true,
"requires": {}
"requires": {
"ajv": "^8.0.0"
}
},
"json-schema-traverse": {
"version": "1.0.0",
@@ -16995,7 +17001,9 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
"dev": true,
"requires": {}
"requires": {
"ajv": "^8.0.0"
}
},
"json-schema-traverse": {
"version": "1.0.0",
@@ -17073,7 +17081,9 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
"dev": true,
"requires": {}
"requires": {
"ajv": "^8.0.0"
}
},
"json-schema-traverse": {
"version": "1.0.0",
@@ -18622,7 +18632,9 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
"dev": true,
"requires": {}
"requires": {
"ajv": "^8.0.0"
}
},
"json-schema-traverse": {
"version": "1.0.0",