Fixed account creation

This commit is contained in:
mdecimus 2023-12-26 11:17:22 +01:00
parent 7ea3460469
commit bb760bc1f9
7 changed files with 65 additions and 28 deletions

View file

@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. This projec
## [0.5.0] - 2023-12-27
This version requires a database migration and introduces breaking changes in the configuration file. Please read the [UPGRADING.md](UPGRADING.md) file for more information.
## Added
- Performance enhancements:
- Messages are parsed only once and their offsets stored in the database, which avoids having to parse them on every `FETCH` request.
@ -20,6 +22,7 @@ All notable changes to this project will be documented in this file. This projec
- IMAP4rev1 `Recent` flag support, which improves compatibility with old IMAP clients.
- LDAP bind authentication, to support some LDAP servers such as `lldap` which do not expose the userPassword attribute.
- Messages marked a spam by the spam filter can now be automatically moved to the account's `Junk Mail` folder.
- Automatic creation of JMAP identities.
### Changed

View file

@ -22,11 +22,14 @@
*/
use jmap_proto::types::collection::Collection;
use pwhash::sha512_crypt;
use store::{
rand::{distributions::Alphanumeric, thread_rng, Rng},
write::{
assert::HashedValue, key::DeserializeBigEndian, BatchBuilder, DirectoryClass, ValueClass,
assert::HashedValue, key::DeserializeBigEndian, BatchBuilder, BitmapClass, DirectoryClass,
ValueClass,
},
Deserialize, IterateParams, Serialize, Store, ValueKey, U32_LEN,
BitmapKey, Deserialize, IterateParams, Serialize, Store, ValueKey, U32_LEN,
};
use crate::{DirectoryError, ManagementError, Principal, QueryBy, Type};
@ -210,6 +213,9 @@ impl ManageDirectory for Store {
let mut batch = BatchBuilder::new();
let ptype = PrincipalIdType::new(principal.id, principal.typ.into_base_type()).serialize();
batch
.with_account_id(u32::MAX)
.with_collection(Collection::Principal)
.create_document(principal.id)
.assert_value(
ValueClass::Directory(DirectoryClass::NameToId(
principal.name.clone().into_bytes(),
@ -902,6 +908,7 @@ impl ManageDirectory for Store {
}
async fn init(self) -> crate::Result<Self> {
// Create admin account if requested
if let (Ok(admin_user), Ok(admin_pass)) = (
std::env::var("SET_ADMIN_USER"),
std::env::var("SET_ADMIN_PASS"),
@ -933,6 +940,43 @@ impl ManageDirectory for Store {
}
std::process::exit(0);
}
// Create a default administrator account if none exists
if self
.get_bitmap(BitmapKey {
account_id: u32::MAX,
collection: Collection::Principal.into(),
class: BitmapClass::DocumentIds,
block_num: 0,
})
.await?
.unwrap_or_default()
.is_empty()
{
let secret = thread_rng()
.sample_iter(Alphanumeric)
.take(12)
.map(char::from)
.collect::<String>();
let hashed_secret = sha512_crypt::hash(&secret).unwrap();
self.create_account(Principal {
typ: Type::Superuser,
quota: 0,
name: "admin".to_string(),
secrets: vec![hashed_secret],
emails: vec![],
member_of: vec![],
description: "Superuser".to_string().into(),
..Default::default()
})
.await?;
tracing::info!(
"Created default administrator account \"admin\" with password {secret:?}."
)
}
Ok(self)
}
}

View file

@ -33,7 +33,6 @@ use base64::{engine::general_purpose, Engine};
use clap::{Parser, ValueEnum};
use dialoguer::{console::Term, theme::ColorfulTheme, Input, Select};
use openssl::rsa::Rsa;
use pwhash::sha512_crypt;
use rand::{distributions::Alphanumeric, thread_rng, Rng};
const CONFIG_URL: &str = "https://get.stalw.art/resources/config.zip";
@ -635,19 +634,9 @@ fn main() -> std::io::Result<()> {
}
if is_internal {
let secret = thread_rng()
.sample_iter(Alphanumeric)
.take(12)
.map(char::from)
.collect::<String>();
let hashed_secret = sha512_crypt::hash(&secret).unwrap();
eprintln!(
"\n🔑 To create the administrator account 'admin' with password '{secret}', execute:\n🔑 ",
"\n🔑 The administrator account is 'admin' and the password can be found in the log files at {}/logs.", base_path.display()
);
eprintln!(
"🔑 $ SET_ADMIN_USER=\"admin\" SET_ADMIN_PASS=\"{hashed_secret}\" {}/bin/stalwart-mail --config={}/etc/config.toml",
base_path.display(), base_path.display()
)
}
eprintln!("\n🎉 Installation completed!\n\n{dkim_instructions}\n");

View file

@ -45,6 +45,17 @@ static GLOBAL: Jemalloc = Jemalloc;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let config = Config::init();
// Enable tracing
let _tracer = enable_tracing(
&config,
&format!(
"Starting Stalwart Mail Server v{}...",
env!("CARGO_PKG_VERSION"),
),
)
.failed("Failed to enable tracing");
let servers = config.parse_servers().failed("Invalid configuration");
let stores = config.parse_stores().await.failed("Invalid configuration");
let directory = config
@ -63,16 +74,6 @@ async fn main() -> std::io::Result<()> {
// Bind ports and drop privileges
servers.bind(&config);
// Enable tracing
let _tracer = enable_tracing(
&config,
&format!(
"Starting Stalwart Mail Server v{}...",
env!("CARGO_PKG_VERSION"),
),
)
.failed("Failed to enable tracing");
// Init servers
let (delivery_tx, delivery_rx) = mpsc::channel(IPC_CHANNEL_BUFFER);
let smtp = SMTP::init(&config, &servers, &stores, &directory, delivery_tx)

View file

@ -146,7 +146,7 @@ impl<T: AsyncWrite + AsyncRead + Unpin> Session<T> {
Ok(len)
}
Err(err) => {
tracing::debug!(
tracing::trace!(
parent: &self.span,
event = "error",
"Failed to read from stream: {:?}", err

View file

@ -369,7 +369,7 @@ impl<T: AsyncWrite + AsyncRead + Unpin> Session<T> {
Err(err) => err,
};
tracing::debug!(parent: &self.span,
tracing::trace!(parent: &self.span,
event = "error",
"Failed to write to stream: {:?}", err);
Err(())
@ -389,7 +389,7 @@ impl<T: AsyncWrite + AsyncRead + Unpin> Session<T> {
Ok(len)
}
Err(err) => {
tracing::debug!(
tracing::trace!(
parent: &self.span,
event = "error",
"Failed to read from stream: {:?}", err

View file

@ -164,7 +164,7 @@ impl Server {
};
}
Err(err) => {
tracing::debug!(context = "io",
tracing::trace!(context = "io",
event = "error",
instance = instance.id,
protocol = ?instance.protocol,