mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
misc fixes
This commit is contained in:
@@ -3,7 +3,7 @@ CREATE TABLE IF NOT EXISTS tor
|
|||||||
(
|
(
|
||||||
package TEXT NOT NULL,
|
package TEXT NOT NULL,
|
||||||
interface TEXT NOT NULL,
|
interface TEXT NOT NULL,
|
||||||
key BLOB NOT NULL,
|
key BLOB NOT NULL CHECK (length(key) = 64),
|
||||||
PRIMARY KEY (package, interface)
|
PRIMARY KEY (package, interface)
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS session
|
CREATE TABLE IF NOT EXISTS session
|
||||||
@@ -19,7 +19,7 @@ CREATE TABLE IF NOT EXISTS account
|
|||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY CHECK (id = 0),
|
id INTEGER PRIMARY KEY CHECK (id = 0),
|
||||||
password TEXT NOT NULL,
|
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
|
CREATE TABLE IF NOT EXISTS ssh_keys
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use serde_json::Value;
|
|||||||
use crate::id::{Id, ImageId};
|
use crate::id::{Id, ImageId};
|
||||||
use crate::s9pk::manifest::{PackageId, SYSTEM_PACKAGE_ID};
|
use crate::s9pk::manifest::{PackageId, SYSTEM_PACKAGE_ID};
|
||||||
use crate::util::{IoFormat, Version};
|
use crate::util::{IoFormat, Version};
|
||||||
use crate::volume::{Volume, VolumeId, Volumes};
|
use crate::volume::{VolumeId, Volumes};
|
||||||
use crate::{Error, ResultExt, HOST_IP};
|
use crate::{Error, ResultExt, HOST_IP};
|
||||||
|
|
||||||
pub const NET_TLD: &'static str = "embassy";
|
pub const NET_TLD: &'static str = "embassy";
|
||||||
@@ -195,7 +195,7 @@ impl DockerAction {
|
|||||||
let mut res = Vec::with_capacity(
|
let mut res = Vec::with_capacity(
|
||||||
(2 * self.mounts.len()) // --mount <MOUNT_ARG>
|
(2 * self.mounts.len()) // --mount <MOUNT_ARG>
|
||||||
+ (2 * self.shm_size_mb.is_some() as usize) // --shm-size <SHM_SIZE>
|
+ (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...]
|
+ self.args.len(), // [ARG...]
|
||||||
);
|
);
|
||||||
for (volume_id, dst) in &self.mounts {
|
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(OsString::from(Self::container_name(pkg_id, None)).into());
|
||||||
res.push(OsStr::new(&self.entrypoint).into());
|
res.push(OsStr::new(&self.entrypoint).into());
|
||||||
} else {
|
} else {
|
||||||
|
res.push(OsStr::new("--log-driver=journald").into());
|
||||||
res.push(OsStr::new("--entrypoint").into());
|
res.push(OsStr::new("--entrypoint").into());
|
||||||
res.push(OsStr::new(&self.entrypoint).into());
|
res.push(OsStr::new(&self.entrypoint).into());
|
||||||
if self.system {
|
if self.system {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ pub async fn login(
|
|||||||
res.headers.insert(
|
res.headers.insert(
|
||||||
"set-cookie",
|
"set-cookie",
|
||||||
HeaderValue::from_str(&format!(
|
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
|
token
|
||||||
))
|
))
|
||||||
.with_kind(crate::ErrorKind::Unknown)?, // Should be impossible, but don't want to panic
|
.with_kind(crate::ErrorKind::Unknown)?, // Should be impossible, but don't want to panic
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub async fn tor_health_check_daemon(tor_controller: &TorController) {
|
|||||||
json!({
|
json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "echo",
|
"method": "echo",
|
||||||
"params": [{ "message": "Follow the orange rabbit" }],
|
"params": { "message": "Follow the orange rabbit" },
|
||||||
})
|
})
|
||||||
.to_string()
|
.to_string()
|
||||||
.into_bytes(),
|
.into_bytes(),
|
||||||
@@ -28,7 +28,7 @@ pub async fn tor_health_check_daemon(tor_controller: &TorController) {
|
|||||||
.await;
|
.await;
|
||||||
match result {
|
match result {
|
||||||
// if success, do nothing
|
// if success, do nothing
|
||||||
Ok(response) => {}
|
Ok(_) => {}
|
||||||
// if failure, disconnect tor control port, and restart tor controller
|
// if failure, disconnect tor control port, and restart tor controller
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Unable to reach self over tor: {}", e);
|
log::error!("Unable to reach self over tor: {}", e);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ pub mod util;
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use futures::{SinkExt, StreamExt};
|
use futures::{FutureExt, SinkExt, StreamExt};
|
||||||
use patch_db::json_ptr::JsonPointer;
|
use patch_db::json_ptr::JsonPointer;
|
||||||
use patch_db::{Dump, Revision};
|
use patch_db::{Dump, Revision};
|
||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
@@ -34,7 +34,17 @@ async fn ws_handler<
|
|||||||
.await
|
.await
|
||||||
.with_kind(crate::ErrorKind::Network)?
|
.with_kind(crate::ErrorKind::Network)?
|
||||||
.with_kind(crate::ErrorKind::Unknown)?;
|
.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
|
stream
|
||||||
.send(Message::Text(
|
.send(Message::Text(
|
||||||
rpc_toolkit::serde_json::to_string(&dump).with_kind(crate::ErrorKind::Serialization)?,
|
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)?;
|
.with_kind(crate::ErrorKind::Network)?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let rev = sub.recv().await.with_kind(crate::ErrorKind::Database)?;
|
futures::select! {
|
||||||
stream
|
new_rev = sub.recv().fuse() => {
|
||||||
.send(Message::Text(
|
let rev = new_rev.with_kind(crate::ErrorKind::Database)?;
|
||||||
rpc_toolkit::serde_json::to_string(&rev)
|
stream
|
||||||
.with_kind(crate::ErrorKind::Serialization)?,
|
.send(Message::Text(
|
||||||
))
|
rpc_toolkit::serde_json::to_string(&rev)
|
||||||
.await
|
.with_kind(crate::ErrorKind::Serialization)?,
|
||||||
.with_kind(crate::ErrorKind::Network)?;
|
))
|
||||||
|
.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> {
|
pub async fn subscribe(ctx: RpcContext, req: Request<Body>) -> Result<Response<Body>, Error> {
|
||||||
let (parts, body) = req.into_parts();
|
let (parts, body) = req.into_parts();
|
||||||
// is_authed(&ctx, &parts).await?;
|
|
||||||
let req = Request::from_parts(parts, body);
|
let req = Request::from_parts(parts, body);
|
||||||
let (res, ws_fut) = hyper_ws_listener::create_ws(req).with_kind(crate::ErrorKind::Network)?;
|
let (res, ws_fut) = hyper_ws_listener::create_ws(req).with_kind(crate::ErrorKind::Network)?;
|
||||||
if let Some(ws_fut) = ws_fut {
|
if let Some(ws_fut) = ws_fut {
|
||||||
|
|||||||
@@ -59,11 +59,12 @@ pub fn echo(#[arg] message: String) -> Result<String, RpcError> {
|
|||||||
#[command(subcommands(
|
#[command(subcommands(
|
||||||
version::git_info,
|
version::git_info,
|
||||||
echo,
|
echo,
|
||||||
|
developer::init,
|
||||||
s9pk::pack,
|
s9pk::pack,
|
||||||
s9pk::verify,
|
s9pk::verify,
|
||||||
developer::init,
|
|
||||||
inspect::inspect,
|
inspect::inspect,
|
||||||
package,
|
package,
|
||||||
|
net::net,
|
||||||
auth::auth,
|
auth::auth,
|
||||||
db::db,
|
db::db,
|
||||||
))]
|
))]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
|
use rpc_toolkit::command;
|
||||||
use torut::onion::TorSecretKeyV3;
|
use torut::onion::TorSecretKeyV3;
|
||||||
|
|
||||||
use self::interface::{Interface, InterfaceId};
|
use self::interface::{Interface, InterfaceId};
|
||||||
@@ -16,6 +17,11 @@ pub mod mdns;
|
|||||||
pub mod tor;
|
pub mod tor;
|
||||||
pub mod wifi;
|
pub mod wifi;
|
||||||
|
|
||||||
|
#[command(subcommands(tor::tor))]
|
||||||
|
pub fn net() -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub struct NetController {
|
pub struct NetController {
|
||||||
pub tor: TorController,
|
pub tor: TorController,
|
||||||
#[cfg(feature = "avahi")]
|
#[cfg(feature = "avahi")]
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ use std::net::{Ipv4Addr, SocketAddr};
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
use clap::ArgMatches;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use rpc_toolkit::command;
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Sqlite};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
@@ -12,7 +14,9 @@ use torut::control::{AsyncEvent, AuthenticatedConn, ConnError};
|
|||||||
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
|
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
|
||||||
|
|
||||||
use super::interface::{InterfaceId, TorConfig};
|
use super::interface::{InterfaceId, TorConfig};
|
||||||
|
use crate::context::RpcContext;
|
||||||
use crate::s9pk::manifest::PackageId;
|
use crate::s9pk::manifest::PackageId;
|
||||||
|
use crate::util::{display_serializable, IoFormat};
|
||||||
use crate::{Error, ErrorKind, ResultExt as _};
|
use crate::{Error, ErrorKind, ResultExt as _};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -20,6 +24,36 @@ fn random_key() {
|
|||||||
println!("'0x{}'", hex::encode(TorSecretKeyV3::generate().as_bytes()));
|
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>
|
pub async fn os_key<Ex>(secrets: &mut Ex) -> Result<TorSecretKeyV3, Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
||||||
@@ -79,6 +113,10 @@ impl TorController {
|
|||||||
pub async fn embassyd_onion(&self) -> OnionAddressV3 {
|
pub async fn embassyd_onion(&self) -> OnionAddressV3 {
|
||||||
self.0.lock().await.embassyd_onion()
|
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<
|
type AuthenticatedConnection = AuthenticatedConn<
|
||||||
@@ -154,10 +192,7 @@ impl TorControllerInner {
|
|||||||
self.connection
|
self.connection
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
Error::new(
|
Error::new(anyhow!("Missing Tor Control Connection"), ErrorKind::Tor)
|
||||||
anyhow!("Missing Tor Control Connection"),
|
|
||||||
ErrorKind::Unknown,
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
.del_onion(
|
.del_onion(
|
||||||
&key.public()
|
&key.public()
|
||||||
@@ -200,9 +235,13 @@ impl TorControllerInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn add_embassyd_onion(&mut self) -> Result<(), Error> {
|
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
|
self.connection
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.expect("Tor Connection is None")
|
.ok_or_else(|| Error::new(anyhow!("Missing Tor Control Connection"), ErrorKind::Tor))?
|
||||||
.add_onion_v3(
|
.add_onion_v3(
|
||||||
&self.embassyd_tor_key,
|
&self.embassyd_tor_key,
|
||||||
false,
|
false,
|
||||||
@@ -212,6 +251,10 @@ impl TorControllerInner {
|
|||||||
&mut std::iter::once(&(self.embassyd_addr.port(), self.embassyd_addr)),
|
&mut std::iter::once(&(self.embassyd_addr.port(), self.embassyd_addr)),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
log::info!(
|
||||||
|
"Registered Main Tor Service: {}",
|
||||||
|
self.embassyd_tor_key.public().get_onion_address()
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,6 +266,7 @@ impl TorControllerInner {
|
|||||||
let uptime = c.get_info("uptime").await?.parse::<u64>()?;
|
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
|
// we never want to restart the tor daemon if it hasn't been up for at least a half hour
|
||||||
if uptime < 1800 {
|
if uptime < 1800 {
|
||||||
|
self.connection = Some(c); // put it back
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
// when connection closes below, tor daemon is restarted
|
// 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>()?;
|
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
|
// if the new uptime exceeds the one we got at the beginning, it's the same tor daemon, do not proceed
|
||||||
match uptime {
|
match uptime {
|
||||||
Some(uptime) if uptime_new < uptime => {
|
Some(uptime) if uptime_new > uptime => (),
|
||||||
|
_ => {
|
||||||
new_connection.set_async_event_handler(Some(event_handler));
|
new_connection.set_async_event_handler(Some(event_handler));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -289,6 +333,17 @@ impl TorControllerInner {
|
|||||||
fn embassyd_onion(&self) -> OnionAddressV3 {
|
fn embassyd_onion(&self) -> OnionAddressV3 {
|
||||||
self.embassyd_tor_key.public().get_onion_address()
|
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]
|
#[tokio::test]
|
||||||
|
|||||||
24
ui/package-lock.json
generated
24
ui/package-lock.json
generated
@@ -16820,7 +16820,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"core-js": {
|
"core-js": {
|
||||||
"version": "3.16.0",
|
"version": "3.16.0",
|
||||||
@@ -16898,7 +16900,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -16942,7 +16946,9 @@
|
|||||||
"integrity": "sha512-Brah4Uo5/U8v76c6euTwtjVFFaVishwnJrQBYpev1JRh4vjA1F4HY3UzQez41YUCszUCXKagG8v6eVRBHV1gkw==",
|
"integrity": "sha512-Brah4Uo5/U8v76c6euTwtjVFFaVishwnJrQBYpev1JRh4vjA1F4HY3UzQez41YUCszUCXKagG8v6eVRBHV1gkw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -16995,7 +17001,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -17073,7 +17081,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -18622,7 +18632,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user