Администраторы почты из Jambotron: каждый ADMIN управляет ящиками
continuous-integration/drone/pr Build is passing
continuous-integration/drone/pr Build is passing
users.is_admin (V8) — ставит только служебное API (PUT /api/service/accounts с "admin"), ящик сам себя администратором не сделает. MailAdmins: список из конфигурации + выданные Jambotron (загружаются при старте, меняются сразу). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,13 +10,15 @@ import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Who manages mailboxes (Settings → Mailboxes): {@code mailserver.admins} (comma separated), by default the first
|
||||
* mailbox — {@code mailserver.admin.email}, or admin@<first domain>. No role in the database: the list lives in
|
||||
* the configuration, so a stolen mailbox can not make itself an administrator.
|
||||
* mailbox — {@code mailserver.admin.email}, or admin@<first domain>; plus mailboxes Jambotron marks as admin
|
||||
* through the service API ({@code users.is_admin}, V8 — every Jambotron ADMIN). A mailbox can not make itself an
|
||||
* administrator: only the configuration or the service token.
|
||||
*/
|
||||
@Component
|
||||
public class MailAdmins {
|
||||
|
||||
private final Set<String> admins;
|
||||
private final Set<String> granted = java.util.concurrent.ConcurrentHashMap.newKeySet();
|
||||
|
||||
public MailAdmins(@Value("${mailserver.admins:}") String admins,
|
||||
@Value("${mailserver.admin.email:}") String firstMailbox,
|
||||
@@ -31,6 +33,20 @@ public class MailAdmins {
|
||||
}
|
||||
|
||||
public boolean isAdmin(String email) {
|
||||
return email != null && admins.contains(email.toLowerCase(Locale.ROOT));
|
||||
if (email == null) {
|
||||
return false;
|
||||
}
|
||||
String key = email.toLowerCase(Locale.ROOT);
|
||||
return admins.contains(key) || granted.contains(key);
|
||||
}
|
||||
|
||||
/** Given / taken by Jambotron (users.is_admin) — loaded at start and kept here on every change. */
|
||||
public void grant(String email, boolean admin) {
|
||||
String key = email.toLowerCase(Locale.ROOT);
|
||||
if (admin) {
|
||||
granted.add(key);
|
||||
} else {
|
||||
granted.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.mailserver.config;
|
||||
|
||||
import com.mailserver.repository.UserRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/** At start: mailboxes Jambotron made administrators (users.is_admin) → {@link MailAdmins}. */
|
||||
@Component
|
||||
public class MailAdminsLoader {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MailAdminsLoader.class);
|
||||
|
||||
private final UserRepository users;
|
||||
private final MailAdmins admins;
|
||||
|
||||
public MailAdminsLoader(UserRepository users, MailAdmins admins) {
|
||||
this.users = users;
|
||||
this.admins = admins;
|
||||
}
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void load() {
|
||||
users.findAll().filter(user -> user.isAdmin())
|
||||
.doOnNext(user -> admins.grant(user.getEmail(), true))
|
||||
.count()
|
||||
.subscribe(n -> log.info("Mail administrators from Jambotron: {}", n),
|
||||
e -> log.error("Mail administrators from Jambotron not loaded: {}", e.getMessage()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user