mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Compare commits
2 Commits
fix/dry-ru
...
feat/gener
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8401b753fb | ||
|
|
f8efd6e6be |
@@ -2818,6 +2818,13 @@ help.arg.echoip-urls:
|
|||||||
fr_FR: "URLs du service Echo IP pour la détection d'IP externe"
|
fr_FR: "URLs du service Echo IP pour la détection d'IP externe"
|
||||||
pl_PL: "Adresy URL usługi Echo IP do wykrywania zewnętrznego IP"
|
pl_PL: "Adresy URL usługi Echo IP do wykrywania zewnętrznego IP"
|
||||||
|
|
||||||
|
help.arg.ed25519:
|
||||||
|
en_US: "Use Ed25519 instead of NIST P-256"
|
||||||
|
de_DE: "Ed25519 anstelle von NIST P-256 verwenden"
|
||||||
|
es_ES: "Usar Ed25519 en lugar de NIST P-256"
|
||||||
|
fr_FR: "Utiliser Ed25519 au lieu de NIST P-256"
|
||||||
|
pl_PL: "Użyj Ed25519 zamiast NIST P-256"
|
||||||
|
|
||||||
help.arg.emulate-missing-arch:
|
help.arg.emulate-missing-arch:
|
||||||
en_US: "Emulate missing architecture using this one"
|
en_US: "Emulate missing architecture using this one"
|
||||||
de_DE: "Fehlende Architektur mit dieser emulieren"
|
de_DE: "Fehlende Architektur mit dieser emulieren"
|
||||||
@@ -2902,6 +2909,13 @@ help.arg.host-url:
|
|||||||
fr_FR: "URL du serveur StartOS"
|
fr_FR: "URL du serveur StartOS"
|
||||||
pl_PL: "URL serwera StartOS"
|
pl_PL: "URL serwera StartOS"
|
||||||
|
|
||||||
|
help.arg.hostnames:
|
||||||
|
en_US: "Hostnames to include in the certificate"
|
||||||
|
de_DE: "Hostnamen, die in das Zertifikat aufgenommen werden sollen"
|
||||||
|
es_ES: "Nombres de host para incluir en el certificado"
|
||||||
|
fr_FR: "Noms d'hôtes à inclure dans le certificat"
|
||||||
|
pl_PL: "Nazwy hostów do uwzględnienia w certyfikacie"
|
||||||
|
|
||||||
help.arg.icon-path:
|
help.arg.icon-path:
|
||||||
en_US: "Path to service icon file"
|
en_US: "Path to service icon file"
|
||||||
de_DE: "Pfad zur Service-Icon-Datei"
|
de_DE: "Pfad zur Service-Icon-Datei"
|
||||||
@@ -5150,6 +5164,13 @@ about.manage-query-dns:
|
|||||||
fr_FR: "Gérer et interroger le DNS"
|
fr_FR: "Gérer et interroger le DNS"
|
||||||
pl_PL: "Zarządzaj i odpytuj DNS"
|
pl_PL: "Zarządzaj i odpytuj DNS"
|
||||||
|
|
||||||
|
about.manage-ssl-certificates:
|
||||||
|
en_US: "Manage SSL certificates"
|
||||||
|
de_DE: "SSL-Zertifikate verwalten"
|
||||||
|
es_ES: "Gestionar certificados SSL"
|
||||||
|
fr_FR: "Gérer les certificats SSL"
|
||||||
|
pl_PL: "Zarządzaj certyfikatami SSL"
|
||||||
|
|
||||||
about.manage-ssl-vhost-proxy:
|
about.manage-ssl-vhost-proxy:
|
||||||
en_US: "Manage SSL vhost proxy"
|
en_US: "Manage SSL vhost proxy"
|
||||||
de_DE: "SSL-vhost-Proxy verwalten"
|
de_DE: "SSL-vhost-Proxy verwalten"
|
||||||
@@ -5654,6 +5675,13 @@ about.stop-service:
|
|||||||
fr_FR: "Arrêter un service"
|
fr_FR: "Arrêter un service"
|
||||||
pl_PL: "Zatrzymaj usługę"
|
pl_PL: "Zatrzymaj usługę"
|
||||||
|
|
||||||
|
about.ssl-generate-certificate:
|
||||||
|
en_US: "Generate an SSL certificate from the system root CA"
|
||||||
|
de_DE: "SSL-Zertifikat von der System-Root-CA generieren"
|
||||||
|
es_ES: "Generar un certificado SSL desde la CA raíz del sistema"
|
||||||
|
fr_FR: "Générer un certificat SSL depuis l'autorité racine du système"
|
||||||
|
pl_PL: "Wygeneruj certyfikat SSL z głównego CA systemu"
|
||||||
|
|
||||||
about.teardown-rebuild-containers:
|
about.teardown-rebuild-containers:
|
||||||
en_US: "Teardown and rebuild containers"
|
en_US: "Teardown and rebuild containers"
|
||||||
de_DE: "Container abbauen und neu erstellen"
|
de_DE: "Container abbauen und neu erstellen"
|
||||||
|
|||||||
@@ -344,12 +344,17 @@ pub async fn mount_fs<P: AsRef<Path>>(
|
|||||||
.arg(&blockdev_path)
|
.arg(&blockdev_path)
|
||||||
.invoke(ErrorKind::DiskManagement)
|
.invoke(ErrorKind::DiskManagement)
|
||||||
.await?;
|
.await?;
|
||||||
// Defragment after conversion for optimal performance
|
// Delete ext2_saved subvolume and defragment after conversion
|
||||||
let tmp_mount = datadir.as_ref().join(format!("{name}.convert-tmp"));
|
let tmp_mount = datadir.as_ref().join(format!("{name}.convert-tmp"));
|
||||||
tokio::fs::create_dir_all(&tmp_mount).await?;
|
tokio::fs::create_dir_all(&tmp_mount).await?;
|
||||||
BlockDev::new(&blockdev_path)
|
BlockDev::new(&blockdev_path)
|
||||||
.mount(&tmp_mount, ReadWrite)
|
.mount(&tmp_mount, ReadWrite)
|
||||||
.await?;
|
.await?;
|
||||||
|
Command::new("btrfs")
|
||||||
|
.args(["subvolume", "delete"])
|
||||||
|
.arg(tmp_mount.join("ext2_saved"))
|
||||||
|
.invoke(ErrorKind::DiskManagement)
|
||||||
|
.await?;
|
||||||
Command::new("btrfs")
|
Command::new("btrfs")
|
||||||
.args(["filesystem", "defragment", "-r"])
|
.args(["filesystem", "defragment", "-r"])
|
||||||
.arg(&tmp_mount)
|
.arg(&tmp_mount)
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ pub fn net_api<C: Context>() -> ParentHandler<C> {
|
|||||||
"tunnel",
|
"tunnel",
|
||||||
tunnel::tunnel_api::<C>().with_about("about.manage-tunnels"),
|
tunnel::tunnel_api::<C>().with_about("about.manage-tunnels"),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
"ssl",
|
||||||
|
ssl::ssl_api::<C>().with_about("about.manage-ssl-certificates"),
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
"vhost",
|
"vhost",
|
||||||
vhost::vhost_api::<C>().with_about("about.manage-ssl-vhost-proxy"),
|
vhost::vhost_api::<C>().with_about("about.manage-ssl-vhost-proxy"),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use std::path::Path;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use imbl_value::InternedString;
|
use imbl_value::InternedString;
|
||||||
use libc::time_t;
|
use libc::time_t;
|
||||||
@@ -21,16 +22,19 @@ use openssl::x509::extension::{
|
|||||||
use openssl::x509::{X509, X509Builder, X509NameBuilder, X509Ref};
|
use openssl::x509::{X509, X509Builder, X509NameBuilder, X509Ref};
|
||||||
use openssl::*;
|
use openssl::*;
|
||||||
use patch_db::HasModel;
|
use patch_db::HasModel;
|
||||||
|
use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio_rustls::rustls::ServerConfig;
|
use tokio_rustls::rustls::ServerConfig;
|
||||||
use tokio_rustls::rustls::crypto::CryptoProvider;
|
use tokio_rustls::rustls::crypto::CryptoProvider;
|
||||||
use tokio_rustls::rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
|
use tokio_rustls::rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
|
||||||
use tokio_rustls::rustls::server::ClientHello;
|
use tokio_rustls::rustls::server::ClientHello;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
use ts_rs::TS;
|
||||||
use visit_rs::Visit;
|
use visit_rs::Visit;
|
||||||
|
|
||||||
use crate::SOURCE_DATE;
|
use crate::SOURCE_DATE;
|
||||||
use crate::account::AccountInfo;
|
use crate::account::AccountInfo;
|
||||||
|
use crate::context::{CliContext, RpcContext};
|
||||||
use crate::db::model::Database;
|
use crate::db::model::Database;
|
||||||
use crate::db::{DbAccess, DbAccessMut};
|
use crate::db::{DbAccess, DbAccessMut};
|
||||||
use crate::hostname::ServerHostname;
|
use crate::hostname::ServerHostname;
|
||||||
@@ -39,7 +43,7 @@ use crate::net::gateway::GatewayInfo;
|
|||||||
use crate::net::tls::{TlsHandler, TlsHandlerAction};
|
use crate::net::tls::{TlsHandler, TlsHandlerAction};
|
||||||
use crate::net::web_server::{Accept, ExtractVisitor, TcpMetadata, extract};
|
use crate::net::web_server::{Accept, ExtractVisitor, TcpMetadata, extract};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::util::serde::Pem;
|
use crate::util::serde::{HandlerExtSerde, Pem};
|
||||||
|
|
||||||
pub fn should_use_cert(cert: &X509Ref) -> Result<bool, ErrorStack> {
|
pub fn should_use_cert(cert: &X509Ref) -> Result<bool, ErrorStack> {
|
||||||
Ok(cert
|
Ok(cert
|
||||||
@@ -592,6 +596,85 @@ pub fn make_self_signed(applicant: (&PKey<Private>, &SANInfo)) -> Result<X509, E
|
|||||||
Ok(cert)
|
Ok(cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ssl_api<C: Context>() -> ParentHandler<C> {
|
||||||
|
ParentHandler::new().subcommand(
|
||||||
|
"generate-certificate",
|
||||||
|
from_fn_async(generate_certificate)
|
||||||
|
.with_display_serializable()
|
||||||
|
.with_custom_display_fn(|_, res: GenerateCertificateResponse| {
|
||||||
|
println!("Private Key:");
|
||||||
|
print!("{}", res.key);
|
||||||
|
println!("\nCertificate Chain:");
|
||||||
|
print!("{}", res.fullchain);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.with_about("about.ssl-generate-certificate")
|
||||||
|
.with_call_remote::<CliContext>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, Parser, TS)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[command(rename_all = "kebab-case")]
|
||||||
|
#[group(skip)]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct GenerateCertificateParams {
|
||||||
|
#[arg(help = "help.arg.hostnames")]
|
||||||
|
pub hostnames: Vec<String>,
|
||||||
|
#[arg(long, help = "help.arg.ed25519")]
|
||||||
|
#[serde(default)]
|
||||||
|
pub ed25519: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, TS)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct GenerateCertificateResponse {
|
||||||
|
pub key: String,
|
||||||
|
pub fullchain: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn generate_certificate(
|
||||||
|
ctx: RpcContext,
|
||||||
|
GenerateCertificateParams { hostnames, ed25519 }: GenerateCertificateParams,
|
||||||
|
) -> Result<GenerateCertificateResponse, Error> {
|
||||||
|
let peek = ctx.db.peek().await;
|
||||||
|
let cert_store = peek.as_private().as_key_store().as_local_certs();
|
||||||
|
let int_key = cert_store.as_int_key().de()?.0;
|
||||||
|
let int_cert = cert_store.as_int_cert().de()?.0;
|
||||||
|
let root_cert = cert_store.as_root_cert().de()?.0;
|
||||||
|
drop(peek);
|
||||||
|
|
||||||
|
let hostnames: BTreeSet<InternedString> = hostnames.into_iter().map(InternedString::from).collect();
|
||||||
|
let san_info = SANInfo::new(&hostnames);
|
||||||
|
|
||||||
|
let (key, cert) = if ed25519 {
|
||||||
|
let key = PKey::generate_ed25519()?;
|
||||||
|
let cert = make_leaf_cert((&int_key, &int_cert), (&key, &san_info))?;
|
||||||
|
(key, cert)
|
||||||
|
} else {
|
||||||
|
let key = gen_nistp256()?;
|
||||||
|
let cert = make_leaf_cert((&int_key, &int_cert), (&key, &san_info))?;
|
||||||
|
(key, cert)
|
||||||
|
};
|
||||||
|
|
||||||
|
let key_pem =
|
||||||
|
String::from_utf8(key.private_key_to_pem_pkcs8()?).with_kind(ErrorKind::Utf8)?;
|
||||||
|
let fullchain_pem = String::from_utf8(
|
||||||
|
[&cert, &int_cert, &root_cert]
|
||||||
|
.into_iter()
|
||||||
|
.map(|c| c.to_pem())
|
||||||
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
|
.concat(),
|
||||||
|
)
|
||||||
|
.with_kind(ErrorKind::Utf8)?;
|
||||||
|
|
||||||
|
Ok(GenerateCertificateResponse {
|
||||||
|
key: key_pem,
|
||||||
|
fullchain: fullchain_pem,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub struct RootCaTlsHandler<M: HasModel> {
|
pub struct RootCaTlsHandler<M: HasModel> {
|
||||||
pub db: TypedPatchDb<M>,
|
pub db: TypedPatchDb<M>,
|
||||||
pub crypto_provider: Arc<CryptoProvider>,
|
pub crypto_provider: Arc<CryptoProvider>,
|
||||||
|
|||||||
6
sdk/base/lib/osBindings/GenerateCertificateParams.ts
Normal file
6
sdk/base/lib/osBindings/GenerateCertificateParams.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type GenerateCertificateParams = {
|
||||||
|
hostnames: Array<string>
|
||||||
|
ed25519: boolean
|
||||||
|
}
|
||||||
3
sdk/base/lib/osBindings/GenerateCertificateResponse.ts
Normal file
3
sdk/base/lib/osBindings/GenerateCertificateResponse.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type GenerateCertificateResponse = { key: string; fullchain: string }
|
||||||
@@ -106,6 +106,8 @@ export { FullProgress } from './FullProgress'
|
|||||||
export { GatewayId } from './GatewayId'
|
export { GatewayId } from './GatewayId'
|
||||||
export { GatewayInfo } from './GatewayInfo'
|
export { GatewayInfo } from './GatewayInfo'
|
||||||
export { GatewayType } from './GatewayType'
|
export { GatewayType } from './GatewayType'
|
||||||
|
export { GenerateCertificateParams } from './GenerateCertificateParams'
|
||||||
|
export { GenerateCertificateResponse } from './GenerateCertificateResponse'
|
||||||
export { GetActionInputParams } from './GetActionInputParams'
|
export { GetActionInputParams } from './GetActionInputParams'
|
||||||
export { GetContainerIpParams } from './GetContainerIpParams'
|
export { GetContainerIpParams } from './GetContainerIpParams'
|
||||||
export { GetHostInfoParams } from './GetHostInfoParams'
|
export { GetHostInfoParams } from './GetHostInfoParams'
|
||||||
|
|||||||
Reference in New Issue
Block a user