提交Git

This commit is contained in:
Peijun Zhao
2026-05-10 12:59:00 +08:00
commit b0aaea9fb3
2544 changed files with 545276 additions and 0 deletions
@@ -0,0 +1,297 @@
package com.aluer.console;
import com.aluer.ai.AluerSovereignEngine;
import com.aluer.audit.SecurityAuditService;
import com.aluer.config.ServerGuardConfig;
import com.aluer.kernel.AluerKernelEngine;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
@Service
public class AluerEngineHandshakeService {
private final ServerGuardConfig config;
private final AluerSovereignEngine aluerSovereignEngine;
private final AluerKernelEngine aluerKernelEngine;
private final AluerMirageShieldService aluerMirageShieldService;
private final SecurityAuditService securityAuditService;
private final Map<String, HandshakeGrant> grants = new ConcurrentHashMap<>();
private final ConcurrentLinkedDeque<HandshakeRecord> history = new ConcurrentLinkedDeque<>();
public AluerEngineHandshakeService(ServerGuardConfig config,
AluerSovereignEngine aluerSovereignEngine,
AluerKernelEngine aluerKernelEngine,
AluerMirageShieldService aluerMirageShieldService,
SecurityAuditService securityAuditService) {
this.config = config;
this.aluerSovereignEngine = aluerSovereignEngine;
this.aluerKernelEngine = aluerKernelEngine;
this.aluerMirageShieldService = aluerMirageShieldService;
this.securityAuditService = securityAuditService;
}
public HandshakeResult requestSshHandshake(HandshakeIntent intent) {
String host = requireText(intent.host(), "host");
String username = requireText(intent.username(), "username");
int port = intent.port() > 0 ? intent.port() : 22;
String purpose = intent.purpose() == null || intent.purpose().isBlank() ? "ssh-connect" : intent.purpose().trim();
cleanupExpiredGrants();
Map<String, Object> engineStatus = aluerSovereignEngine.getEngineStatus();
AluerKernelEngine.KernelPulse pulse = aluerKernelEngine.runKernelPulse("ssh-handshake:" + host + ":" + username);
Map<String, Object> shieldStatus = aluerMirageShieldService.getShieldStatus();
int kernelHeat = (int) Math.round(pulse.getHeat());
int resonance = (int) Math.round(pulse.getResonance());
int riskScore = toInt(shieldStatus.get("riskScore"));
String shieldMode = String.valueOf(shieldStatus.getOrDefault("currentMode", "OBSERVE"));
String workflow = pulse.getDirective().getWorkflow();
boolean handshakeRequired = config.getDashboard().getSshGateway().isRequireEngineHandshake();
boolean approved = !handshakeRequired || (kernelHeat < 96 && riskScore < 97);
String token = approved ? UUID.randomUUID().toString() : "";
long ttlSeconds = Math.max(10, config.getDashboard().getSshGateway().getHandshakeTtlSeconds());
long expiresAt = System.currentTimeMillis() + ttlSeconds * 1000L;
String message = approved
? "Sovereign handshake approved. Session may proceed."
: "Main engine declined SSH session while the node is under critical defensive pressure.";
if (approved && handshakeRequired) {
grants.put(token, new HandshakeGrant(token, host, port, username, expiresAt, purpose, shieldMode, kernelHeat, riskScore));
}
HandshakeRecord record = new HandshakeRecord(host, port, username, purpose, approved, shieldMode, kernelHeat, riskScore, workflow, expiresAt);
rememberRecord(record);
securityAuditService.logEvent("ALUER_HANDSHAKE", username + "@" + host, approved ? "APPROVED" : "DENIED", purpose);
return new HandshakeResult(
approved,
token,
message,
shieldMode,
workflow,
kernelHeat,
resonance,
riskScore,
expiresAt,
engineStatus.getOrDefault("engine", "ALUER_SOVEREIGN_LOOP").toString()
);
}
public HandshakeGrant consumeSshGrant(String token, String host, int port, String username) {
cleanupExpiredGrants();
if (!config.getDashboard().getSshGateway().isRequireEngineHandshake()) {
return new HandshakeGrant("", host, port, username, 0, "ssh-connect", "BYPASS", 0, 0);
}
String normalizedToken = requireText(token, "handshakeToken");
HandshakeGrant grant = grants.remove(normalizedToken);
if (grant == null) {
throw new IllegalArgumentException("主引擎握手令牌不存在或已过期");
}
if (grant.expiresAt < System.currentTimeMillis()) {
throw new IllegalArgumentException("主引擎握手令牌已过期");
}
if (!grant.host.equals(host) || grant.port != port || !grant.username.equals(username)) {
throw new IllegalArgumentException("主引擎握手令牌与目标节点不匹配");
}
return grant;
}
public Map<String, Object> getStatus() {
cleanupExpiredGrants();
Map<String, Object> result = new LinkedHashMap<>();
result.put("required", config.getDashboard().getSshGateway().isRequireEngineHandshake());
result.put("ttlSeconds", config.getDashboard().getSshGateway().getHandshakeTtlSeconds());
result.put("activeGrants", grants.size());
if (!history.isEmpty()) {
result.put("lastHandshake", history.peekFirst().toMap());
}
return result;
}
private void cleanupExpiredGrants() {
long now = System.currentTimeMillis();
grants.entrySet().removeIf(entry -> entry.getValue().expiresAt < now);
}
private void rememberRecord(HandshakeRecord record) {
history.offerFirst(record);
while (history.size() > 120) {
history.pollLast();
}
}
private int toInt(Object value) {
if (value instanceof Number number) {
return number.intValue();
}
try {
return value == null ? 0 : Integer.parseInt(String.valueOf(value));
} catch (NumberFormatException ignored) {
return 0;
}
}
private String requireText(String value, String field) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException(field + " 不能为空");
}
return value.trim();
}
public record HandshakeIntent(
String host,
int port,
String username,
String purpose
) {
}
public static class HandshakeResult {
private final boolean approved;
private final String token;
private final String message;
private final String shieldMode;
private final String workflow;
private final int kernelHeat;
private final int resonance;
private final int riskScore;
private final long expiresAt;
private final String engine;
public HandshakeResult(boolean approved,
String token,
String message,
String shieldMode,
String workflow,
int kernelHeat,
int resonance,
int riskScore,
long expiresAt,
String engine) {
this.approved = approved;
this.token = token;
this.message = message;
this.shieldMode = shieldMode;
this.workflow = workflow;
this.kernelHeat = kernelHeat;
this.resonance = resonance;
this.riskScore = riskScore;
this.expiresAt = expiresAt;
this.engine = engine;
}
public boolean isApproved() { return approved; }
public String getToken() { return token; }
public String getMessage() { return message; }
public String getShieldMode() { return shieldMode; }
public String getWorkflow() { return workflow; }
public int getKernelHeat() { return kernelHeat; }
public int getResonance() { return resonance; }
public int getRiskScore() { return riskScore; }
public long getExpiresAt() { return expiresAt; }
public String getEngine() { return engine; }
}
public static class HandshakeGrant {
private final String token;
private final String host;
private final int port;
private final String username;
private final long expiresAt;
private final String purpose;
private final String shieldMode;
private final int kernelHeat;
private final int riskScore;
public HandshakeGrant(String token,
String host,
int port,
String username,
long expiresAt,
String purpose,
String shieldMode,
int kernelHeat,
int riskScore) {
this.token = token;
this.host = host;
this.port = port;
this.username = username;
this.expiresAt = expiresAt;
this.purpose = purpose;
this.shieldMode = shieldMode;
this.kernelHeat = kernelHeat;
this.riskScore = riskScore;
}
public String getToken() { return token; }
public String getHost() { return host; }
public int getPort() { return port; }
public String getUsername() { return username; }
public long getExpiresAt() { return expiresAt; }
public String getPurpose() { return purpose; }
public String getShieldMode() { return shieldMode; }
public int getKernelHeat() { return kernelHeat; }
public int getRiskScore() { return riskScore; }
}
public static class HandshakeRecord {
private final String host;
private final int port;
private final String username;
private final String purpose;
private final boolean approved;
private final String shieldMode;
private final int kernelHeat;
private final int riskScore;
private final String workflow;
private final long expiresAt;
private final long timestamp = Instant.now().toEpochMilli();
public HandshakeRecord(String host,
int port,
String username,
String purpose,
boolean approved,
String shieldMode,
int kernelHeat,
int riskScore,
String workflow,
long expiresAt) {
this.host = host;
this.port = port;
this.username = username;
this.purpose = purpose;
this.approved = approved;
this.shieldMode = shieldMode;
this.kernelHeat = kernelHeat;
this.riskScore = riskScore;
this.workflow = workflow;
this.expiresAt = expiresAt;
}
public Map<String, Object> toMap() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("host", host);
result.put("port", port);
result.put("username", username);
result.put("purpose", purpose);
result.put("approved", approved);
result.put("shieldMode", shieldMode);
result.put("kernelHeat", kernelHeat);
result.put("riskScore", riskScore);
result.put("workflow", workflow);
result.put("expiresAt", expiresAt);
result.put("timestamp", timestamp);
return result;
}
}
}
@@ -0,0 +1,448 @@
package com.aluer.console;
import com.aluer.audit.SecurityAuditService;
import com.aluer.config.ServerGuardConfig;
import com.aluer.kernel.AluerKernelEngine;
import com.aluer.kernel.AluerKernelTaskBus;
import com.aluer.kernel.AluerSelfHealingOrchestrator;
import com.aluer.security.CloudflareIntegrationService;
import com.aluer.security.DDoSDefenseCoordinator;
import com.aluer.security.DistributedAttackMitigationService;
import com.aluer.security.HostEnforcementService;
import com.aluer.security.LoadBalancerService;
import com.aluer.security.NetworkThreatFusionService;
import com.aluer.security.SecurityBaselineHardeningService;
import com.aluer.security.CommandExecutionGuardService;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedDeque;
@Service
public class AluerMirageShieldService {
private final ServerGuardConfig config;
private final NetworkThreatFusionService networkThreatFusionService;
private final DDoSDefenseCoordinator ddosDefenseCoordinator;
private final DistributedAttackMitigationService distributedAttackMitigationService;
private final CloudflareIntegrationService cloudflareIntegrationService;
private final HostEnforcementService hostEnforcementService;
private final LoadBalancerService loadBalancerService;
private final SecurityBaselineHardeningService securityBaselineHardeningService;
private final CommandExecutionGuardService commandExecutionGuardService;
private final AluerKernelEngine aluerKernelEngine;
private final AluerKernelTaskBus aluerKernelTaskBus;
private final AluerSelfHealingOrchestrator aluerSelfHealingOrchestrator;
private final SecurityAuditService securityAuditService;
private final ConcurrentLinkedDeque<ShieldTransition> transitions = new ConcurrentLinkedDeque<>();
private volatile ShieldMode currentMode = ShieldMode.OBSERVE;
public AluerMirageShieldService(ServerGuardConfig config,
NetworkThreatFusionService networkThreatFusionService,
DDoSDefenseCoordinator ddosDefenseCoordinator,
DistributedAttackMitigationService distributedAttackMitigationService,
CloudflareIntegrationService cloudflareIntegrationService,
HostEnforcementService hostEnforcementService,
LoadBalancerService loadBalancerService,
SecurityBaselineHardeningService securityBaselineHardeningService,
CommandExecutionGuardService commandExecutionGuardService,
AluerKernelEngine aluerKernelEngine,
AluerKernelTaskBus aluerKernelTaskBus,
AluerSelfHealingOrchestrator aluerSelfHealingOrchestrator,
SecurityAuditService securityAuditService) {
this.config = config;
this.networkThreatFusionService = networkThreatFusionService;
this.ddosDefenseCoordinator = ddosDefenseCoordinator;
this.distributedAttackMitigationService = distributedAttackMitigationService;
this.cloudflareIntegrationService = cloudflareIntegrationService;
this.hostEnforcementService = hostEnforcementService;
this.loadBalancerService = loadBalancerService;
this.securityBaselineHardeningService = securityBaselineHardeningService;
this.commandExecutionGuardService = commandExecutionGuardService;
this.aluerKernelEngine = aluerKernelEngine;
this.aluerKernelTaskBus = aluerKernelTaskBus;
this.aluerSelfHealingOrchestrator = aluerSelfHealingOrchestrator;
this.securityAuditService = securityAuditService;
}
public Map<String, Object> getShieldStatus() {
ShieldSnapshot snapshot = buildSnapshot("status");
Map<String, Object> result = snapshot.toMap();
result.put("enabled", config.getSecurity().getShield().isEnabled());
result.put("currentMode", currentMode.name());
result.put("recommendedMode", recommendMode(snapshot).name());
result.put("deterrenceMessage", composeDeterrenceNotice(snapshot.primaryOffenderIp, "access denied"));
if (!transitions.isEmpty()) {
result.put("lastTransition", transitions.peekFirst().toMap());
}
return result;
}
public Map<String, Object> engage(String requestedMode, String reason) {
if (!config.getSecurity().getShield().isEnabled()) {
return Map.of("enabled", false, "status", "disabled");
}
ShieldSnapshot snapshot = buildSnapshot("engage");
ShieldMode targetMode = parseMode(requestedMode, recommendMode(snapshot));
List<Map<String, Object>> actions = new ArrayList<>();
String actionReason = reason == null || reason.isBlank() ? "manual-console-engage" : reason.trim();
List<Map<String, Object>> topOffenders = networkThreatFusionService.getTopRiskIPs(
Math.max(1, config.getSecurity().getShield().getEdgeChallengeOffenderLimit())
);
String notice = composeDeterrenceNotice(snapshot.primaryOffenderIp, actionReason);
switch (targetMode) {
case OBSERVE -> {
distributedAttackMitigationService.setDefenseLevel("LOW");
loadBalancerService.setAlgorithm("ROUND_ROBIN");
actions.add(action("defense-level", "LOW", true));
actions.add(action("load-balancer", "ROUND_ROBIN", true));
}
case FORTIFY -> {
distributedAttackMitigationService.setDefenseLevel("MEDIUM");
cloudflareIntegrationService.setSecurityLevel(resolveZoneId(), "high");
actions.add(action("defense-level", "MEDIUM", true));
actions.add(action("edge-security-level", "high", true));
submitTask(actions, AluerKernelTaskBus.TaskType.SNAPSHOT_STATE, 74, Map.of("reason", actionReason));
submitTask(actions, AluerKernelTaskBus.TaskType.SYNC_DEFENSE_LEVEL, 72, Map.of("defenseLevel", "ELEVATED"));
}
case MIRAGE -> {
distributedAttackMitigationService.setDefenseLevel("HIGH");
loadBalancerService.setAlgorithm("LEAST_CONNECTIONS");
actions.add(action("defense-level", "HIGH", true));
actions.add(action("load-balancer", "LEAST_CONNECTIONS", true));
challengeTopOffenders(actions, topOffenders, notice);
rateLimitTopOffenders(actions, topOffenders, "mirage-shield");
submitTask(actions, AluerKernelTaskBus.TaskType.RELIEVE_PRESSURE, 84, Map.of("reason", actionReason));
submitTask(actions, AluerKernelTaskBus.TaskType.SNAPSHOT_STATE, 76, Map.of("reason", "mirage-forensics"));
}
case SHELTER -> {
distributedAttackMitigationService.setDefenseLevel("HIGH");
loadBalancerService.setAlgorithm("RESPONSE_TIME");
actions.add(action("defense-level", "HIGH", true));
actions.add(action("load-balancer", "RESPONSE_TIME", true));
if (config.getSecurity().getShield().isAutoEnableUnderAttack()) {
CloudflareIntegrationService.EdgeActionResult edgeResult =
cloudflareIntegrationService.setUnderAttackMode(true, actionReason);
actions.add(edgeAction("under-attack", edgeResult));
}
challengeTopOffenders(actions, topOffenders, notice);
blockTopOffenders(actions, topOffenders, "shelter-mode");
submitTask(actions, AluerKernelTaskBus.TaskType.WHITELIST_LOCKDOWN, 95, Map.of(
"reason", actionReason,
"notice", notice
));
submitTask(actions, AluerKernelTaskBus.TaskType.PREPARE_BACKUP, 92, Map.of("reason", "shield-shelter"));
submitTask(actions, AluerKernelTaskBus.TaskType.SNAPSHOT_STATE, 80, Map.of("reason", "shield-shelter"));
actions.add(action("self-healing", aluerSelfHealingOrchestrator.runHealingCycle("mirage-shield").getSummary(), true));
}
case RECOVERY -> {
distributedAttackMitigationService.setDefenseLevel("MEDIUM");
loadBalancerService.setAlgorithm("RESPONSE_TIME");
actions.add(action("defense-level", "MEDIUM", true));
actions.add(action("load-balancer", "RESPONSE_TIME", true));
actions.add(action("self-healing", aluerSelfHealingOrchestrator.runHealingCycle("mirage-recovery").getSummary(), true));
submitTask(actions, AluerKernelTaskBus.TaskType.SYNC_DEFENSE_LEVEL, 72, Map.of("defenseLevel", "ELEVATED"));
}
}
List<AluerKernelTaskBus.KernelTaskResult> dispatched = aluerKernelTaskBus.dispatchQueuedTasks(4);
if (!dispatched.isEmpty()) {
actions.add(action("task-bus-dispatch", dispatched.stream().map(AluerKernelTaskBus.KernelTaskResult::getSummary).toList(), true));
}
currentMode = targetMode;
ShieldTransition transition = new ShieldTransition(targetMode.name(), actionReason, snapshot.riskScore, snapshot.kernelHeat, actions);
rememberTransition(transition);
securityAuditService.logEvent("ALUER_MIRAGE_SHIELD", targetMode.name(), "ENGAGE", actionReason);
Map<String, Object> result = new LinkedHashMap<>();
result.put("status", "engaged");
result.put("mode", targetMode.name());
result.put("reason", actionReason);
result.put("riskScore", snapshot.riskScore);
result.put("deterrenceMessage", notice);
result.put("actions", actions);
result.put("topOffenders", topOffenders);
result.put("transition", transition.toMap());
return result;
}
public List<ShieldTransition> getRecentTransitions(int limit) {
List<ShieldTransition> result = new ArrayList<>();
int count = 0;
for (ShieldTransition transition : transitions) {
if (count++ >= limit) {
break;
}
result.add(transition);
}
return result;
}
public String composeDeterrenceNotice(String ip, String reason) {
if (!config.getSecurity().getShield().isAttackerNoticeEnabled()) {
return "";
}
String source = ip == null || ip.isBlank() ? "unknown-source" : ip;
String details = reason == null || reason.isBlank() ? "policy enforcement" : reason;
return "ALUER NOTICE: source " + source + " has been identified, recorded, and isolated. " + details + ".";
}
private ShieldSnapshot buildSnapshot(String trigger) {
Map<String, Object> posture = networkThreatFusionService.getPosture();
Map<String, Object> ddosPosture = ddosDefenseCoordinator.getPosture();
SecurityBaselineHardeningService.HardeningReport hardening = securityBaselineHardeningService.assessCurrentBaseline();
Map<String, Object> kernel = aluerKernelEngine.getKernelStatus();
@SuppressWarnings("unchecked")
Map<String, Object> lastPulse = (Map<String, Object>) kernel.getOrDefault("lastPulse", Collections.emptyMap());
int postureScore = asInt(posture.get("postureScore"));
int kernelHeat = asInt(lastPulse.get("heat"));
int kernelResonance = asInt(lastPulse.get("resonance"));
int criticalRiskIps = asInt(posture.get("criticalRiskIPs"));
int activeIncidents = asInt(ddosPosture.get("activeIncidents"));
int commandCritical = asInt(commandExecutionGuardService.getStats().get("criticalIncidents"));
int hardeningCritical = hardening.getCriticalCount();
int riskScore = Math.min(100,
Math.max(0, 100 - postureScore)
+ kernelHeat / 2
+ kernelResonance / 3
+ criticalRiskIps * 9
+ activeIncidents * 4
+ commandCritical * 12
+ hardeningCritical * 10
);
List<Map<String, Object>> topOffenders = networkThreatFusionService.getTopRiskIPs(5);
String primaryOffenderIp = topOffenders.isEmpty()
? ""
: String.valueOf(topOffenders.get(0).getOrDefault("ip", ""));
return new ShieldSnapshot(
trigger,
posture,
ddosPosture,
hardening,
kernelHeat,
kernelResonance,
riskScore,
primaryOffenderIp,
topOffenders
);
}
private ShieldMode recommendMode(ShieldSnapshot snapshot) {
if (snapshot.riskScore >= config.getSecurity().getShield().getThreatScoreTrigger()
|| snapshot.kernelHeat >= config.getSecurity().getKernel().getLockdownHeatThreshold()) {
return ShieldMode.SHELTER;
}
if (snapshot.kernelHeat >= config.getSecurity().getShield().getHeatTrigger()
|| snapshot.kernelResonance >= config.getSecurity().getShield().getResonanceTrigger()) {
return ShieldMode.MIRAGE;
}
if (snapshot.riskScore >= config.getSecurity().getShield().getThreatScoreTrigger() - 20) {
return ShieldMode.FORTIFY;
}
return ShieldMode.OBSERVE;
}
private ShieldMode parseMode(String requestedMode, ShieldMode fallback) {
if (requestedMode == null || requestedMode.isBlank()) {
return fallback;
}
try {
return ShieldMode.valueOf(requestedMode.trim().toUpperCase());
} catch (IllegalArgumentException ignored) {
return fallback;
}
}
private void submitTask(List<Map<String, Object>> actions,
AluerKernelTaskBus.TaskType type,
int priority,
Map<String, Object> payload) {
String taskId = aluerKernelTaskBus.submitTask(type, "mirage-shield", priority, payload);
actions.add(action("task:" + type.name(), taskId, true));
}
private void challengeTopOffenders(List<Map<String, Object>> actions,
List<Map<String, Object>> topOffenders,
String notice) {
for (Map<String, Object> offender : topOffenders) {
String ip = String.valueOf(offender.getOrDefault("ip", ""));
if (ip.isBlank() || asInt(offender.get("riskScore")) < 55) {
continue;
}
CloudflareIntegrationService.EdgeActionResult result = cloudflareIntegrationService.applyChallenge(ip, notice);
actions.add(edgeAction("challenge:" + ip, result));
}
}
private void rateLimitTopOffenders(List<Map<String, Object>> actions,
List<Map<String, Object>> topOffenders,
String reason) {
for (Map<String, Object> offender : topOffenders) {
String ip = String.valueOf(offender.getOrDefault("ip", ""));
if (ip.isBlank() || asInt(offender.get("riskScore")) < 60) {
continue;
}
HostEnforcementService.EnforcementActionResult result = hostEnforcementService.rateLimitIp(
ip,
config.getSecurity().getShield().getShelterRateLimitPerMinute(),
reason
);
actions.add(hostAction("rate-limit:" + ip, result));
}
}
private void blockTopOffenders(List<Map<String, Object>> actions,
List<Map<String, Object>> topOffenders,
String reason) {
for (Map<String, Object> offender : topOffenders) {
String ip = String.valueOf(offender.getOrDefault("ip", ""));
if (ip.isBlank() || asInt(offender.get("riskScore")) < 70) {
continue;
}
HostEnforcementService.EnforcementActionResult result = hostEnforcementService.blockIp(
ip,
reason,
config.getSecurity().getHostEnforcement().getDefaultBlockMinutes()
);
actions.add(hostAction("block:" + ip, result));
}
}
private Map<String, Object> action(String type, Object details, boolean success) {
Map<String, Object> result = new LinkedHashMap<>();
result.put("type", type);
result.put("details", details);
result.put("success", success);
result.put("timestamp", Instant.now().toEpochMilli());
return result;
}
private Map<String, Object> edgeAction(String type, CloudflareIntegrationService.EdgeActionResult result) {
return action(type, Map.<String, Object>of(
"success", result.isSuccess(),
"dryRun", result.isDryRun(),
"mode", result.getAction(),
"ip", result.getIp(),
"reason", result.getReason()
), result.isSuccess());
}
private Map<String, Object> hostAction(String type, HostEnforcementService.EnforcementActionResult result) {
return action(type, Map.of(
"success", result.isSuccess(),
"dryRun", result.isDryRun(),
"backend", result.getBackend(),
"status", result.getStatus(),
"ip", result.getIp()
), result.isSuccess());
}
private void rememberTransition(ShieldTransition transition) {
transitions.offerFirst(transition);
while (transitions.size() > 120) {
transitions.pollLast();
}
}
private String resolveZoneId() {
Object zoneId = cloudflareIntegrationService.getStats().get("zoneId");
return zoneId == null ? "" : String.valueOf(zoneId);
}
private int asInt(Object value) {
if (value instanceof Number number) {
return number.intValue();
}
if (value instanceof Collection<?> collection) {
return collection.size();
}
try {
return value == null ? 0 : Integer.parseInt(String.valueOf(value));
} catch (NumberFormatException ignored) {
return 0;
}
}
private enum ShieldMode {
OBSERVE,
FORTIFY,
MIRAGE,
SHELTER,
RECOVERY
}
private record ShieldSnapshot(
String trigger,
Map<String, Object> posture,
Map<String, Object> ddosPosture,
SecurityBaselineHardeningService.HardeningReport hardening,
int kernelHeat,
int kernelResonance,
int riskScore,
String primaryOffenderIp,
List<Map<String, Object>> topOffenders
) {
private Map<String, Object> toMap() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("trigger", trigger);
result.put("riskScore", riskScore);
result.put("kernelHeat", kernelHeat);
result.put("kernelResonance", kernelResonance);
result.put("primaryOffenderIp", primaryOffenderIp);
result.put("topOffenders", topOffenders);
result.put("posture", posture);
result.put("ddos", ddosPosture);
result.put("hardening", hardening.toMap());
return result;
}
}
public static class ShieldTransition {
private final String mode;
private final String reason;
private final int riskScore;
private final int kernelHeat;
private final List<Map<String, Object>> actions;
private final long timestamp;
public ShieldTransition(String mode,
String reason,
int riskScore,
int kernelHeat,
List<Map<String, Object>> actions) {
this.mode = mode;
this.reason = reason;
this.riskScore = riskScore;
this.kernelHeat = kernelHeat;
this.actions = actions == null ? List.of() : new ArrayList<>(actions);
this.timestamp = Instant.now().toEpochMilli();
}
public String getMode() { return mode; }
public String getReason() { return reason; }
public int getRiskScore() { return riskScore; }
public int getKernelHeat() { return kernelHeat; }
public List<Map<String, Object>> getActions() { return actions; }
public long getTimestamp() { return timestamp; }
public Map<String, Object> toMap() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("mode", mode);
result.put("reason", reason);
result.put("riskScore", riskScore);
result.put("kernelHeat", kernelHeat);
result.put("actions", actions);
result.put("timestamp", timestamp);
return result;
}
}
}
@@ -0,0 +1,232 @@
package com.aluer.console;
import com.aluer.ai.AIAutonomousService;
import com.aluer.ai.AluerSovereignEngine;
import com.aluer.audit.SecurityAuditService;
import com.aluer.backup.BackupService;
import com.aluer.config.ServerGuardConfig;
import com.aluer.kernel.AluerKernelEngine;
import com.aluer.kernel.AluerKernelTaskBus;
import com.aluer.kernel.AluerSelfHealingOrchestrator;
import com.aluer.model.MetricsData;
import com.aluer.monitor.ProcessMonitor;
import com.aluer.monitor.ResourceMonitor;
import com.aluer.security.CloudflareIntegrationService;
import com.aluer.security.CommandExecutionGuardService;
import com.aluer.security.DDoSDefenseCoordinator;
import com.aluer.security.DistributedAttackMitigationService;
import com.aluer.security.HostEnforcementService;
import com.aluer.security.LoadBalancerService;
import com.aluer.security.NetworkThreatFusionService;
import com.aluer.security.SecurityBaselineHardeningService;
import com.aluer.service.RconClient;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Service
public class AluerOperationsCenterService {
private final ServerGuardConfig config;
private final ResourceMonitor resourceMonitor;
private final ProcessMonitor processMonitor;
private final RconClient rconClient;
private final BackupService backupService;
private final NetworkThreatFusionService networkThreatFusionService;
private final DDoSDefenseCoordinator ddosDefenseCoordinator;
private final DistributedAttackMitigationService distributedAttackMitigationService;
private final SecurityBaselineHardeningService securityBaselineHardeningService;
private final SecurityAuditService securityAuditService;
private final AluerSovereignEngine aluerSovereignEngine;
private final AIAutonomousService aiAutonomousService;
private final AluerKernelEngine aluerKernelEngine;
private final AluerKernelTaskBus aluerKernelTaskBus;
private final AluerSelfHealingOrchestrator aluerSelfHealingOrchestrator;
private final HostEnforcementService hostEnforcementService;
private final CloudflareIntegrationService cloudflareIntegrationService;
private final LoadBalancerService loadBalancerService;
private final CommandExecutionGuardService commandExecutionGuardService;
private final AluerMirageShieldService aluerMirageShieldService;
private final RemoteSshGatewayService remoteSshGatewayService;
public AluerOperationsCenterService(ServerGuardConfig config,
ResourceMonitor resourceMonitor,
ProcessMonitor processMonitor,
RconClient rconClient,
BackupService backupService,
NetworkThreatFusionService networkThreatFusionService,
DDoSDefenseCoordinator ddosDefenseCoordinator,
DistributedAttackMitigationService distributedAttackMitigationService,
SecurityBaselineHardeningService securityBaselineHardeningService,
SecurityAuditService securityAuditService,
AluerSovereignEngine aluerSovereignEngine,
AIAutonomousService aiAutonomousService,
AluerKernelEngine aluerKernelEngine,
AluerKernelTaskBus aluerKernelTaskBus,
AluerSelfHealingOrchestrator aluerSelfHealingOrchestrator,
HostEnforcementService hostEnforcementService,
CloudflareIntegrationService cloudflareIntegrationService,
LoadBalancerService loadBalancerService,
CommandExecutionGuardService commandExecutionGuardService,
AluerMirageShieldService aluerMirageShieldService,
RemoteSshGatewayService remoteSshGatewayService) {
this.config = config;
this.resourceMonitor = resourceMonitor;
this.processMonitor = processMonitor;
this.rconClient = rconClient;
this.backupService = backupService;
this.networkThreatFusionService = networkThreatFusionService;
this.ddosDefenseCoordinator = ddosDefenseCoordinator;
this.distributedAttackMitigationService = distributedAttackMitigationService;
this.securityBaselineHardeningService = securityBaselineHardeningService;
this.securityAuditService = securityAuditService;
this.aluerSovereignEngine = aluerSovereignEngine;
this.aiAutonomousService = aiAutonomousService;
this.aluerKernelEngine = aluerKernelEngine;
this.aluerKernelTaskBus = aluerKernelTaskBus;
this.aluerSelfHealingOrchestrator = aluerSelfHealingOrchestrator;
this.hostEnforcementService = hostEnforcementService;
this.cloudflareIntegrationService = cloudflareIntegrationService;
this.loadBalancerService = loadBalancerService;
this.commandExecutionGuardService = commandExecutionGuardService;
this.aluerMirageShieldService = aluerMirageShieldService;
this.remoteSshGatewayService = remoteSshGatewayService;
}
public Map<String, Object> buildOverview() {
MetricsData metrics = resourceMonitor.collectMetrics();
Map<String, Object> network = networkThreatFusionService.getPosture();
Map<String, Object> ddos = ddosDefenseCoordinator.getPosture();
Map<String, Object> sovereign = aluerSovereignEngine.getEngineStatus();
Map<String, Object> hardening = securityBaselineHardeningService.getSummary();
Map<String, Object> shield = aluerMirageShieldService.getShieldStatus();
Map<String, Object> ssh = remoteSshGatewayService.getGatewayStatus();
Map<String, Object> server = new LinkedHashMap<>();
server.put("serviceName", config.getMinecraft().getServiceName());
server.put("workingDir", config.getMinecraft().getWorkingDir());
server.put("processRunning", processMonitor.isProcessRunning());
server.put("rconConnected", rconClient.isConnected());
server.put("metrics", Map.of(
"tps", metrics.getTps(),
"cpuUsage", metrics.getCpuUsage(),
"memoryUsage", metrics.getMemoryUsage(),
"onlinePlayers", metrics.getOnlinePlayers(),
"connections", metrics.getConnections(),
"tickTime", metrics.getTickTime()
));
Map<String, Object> defense = new LinkedHashMap<>();
defense.put("network", network);
defense.put("ddos", ddos);
defense.put("sovereign", sovereign);
defense.put("shield", shield);
defense.put("hardening", hardening);
defense.put("cloudEdge", cloudflareIntegrationService.getStats());
defense.put("hostEnforcement", hostEnforcementService.getStats());
defense.put("distributedMitigation", distributedAttackMitigationService.getStats());
defense.put("loadBalancer", loadBalancerService.getStats());
defense.put("commandGuard", commandExecutionGuardService.getStats());
Map<String, Object> kernel = new LinkedHashMap<>();
kernel.put("engine", aluerKernelEngine.getKernelStatus());
kernel.put("taskBus", aluerKernelTaskBus.getBusStatus());
kernel.put("selfHealing", aluerSelfHealingOrchestrator.getStatus());
Map<String, Object> result = new LinkedHashMap<>();
result.put("title", config.getDashboard().getTitle());
result.put("subtitle", config.getDashboard().getSubtitle());
result.put("refreshIntervalSeconds", config.getDashboard().getRefreshIntervalSeconds());
result.put("timestamp", Instant.now().toEpochMilli());
result.put("server", server);
result.put("defense", defense);
result.put("ai", aiAutonomousService.getAutonomousStats());
result.put("kernel", kernel);
result.put("backups", Map.of("count", backupService.getBackupHistory().size()));
result.put("ssh", ssh);
result.put("modules", buildModuleCatalog());
result.put("audit", buildAuditFeed(12));
return result;
}
public List<Map<String, Object>> buildModuleCatalog() {
List<Map<String, Object>> modules = new ArrayList<>();
Map<String, Object> shield = aluerMirageShieldService.getShieldStatus();
Map<String, Object> sovereign = aluerSovereignEngine.getEngineStatus();
Map<String, Object> kernel = aluerKernelEngine.getKernelStatus();
Map<String, Object> taskBus = aluerKernelTaskBus.getBusStatus();
Map<String, Object> selfHealing = aluerSelfHealingOrchestrator.getStatus();
Map<String, Object> ssh = remoteSshGatewayService.getGatewayStatus();
modules.add(module("mirage-shield", "Mirage Shield", String.valueOf(shield.get("currentMode")),
"偏转护盾 / DDoS 防线 / 攻击者告警", intOf(shield.get("riskScore"))));
modules.add(module("sovereign-engine", "Sovereign Loop", String.valueOf(sovereign.get("engine")),
"主控决策环与 DeepSeek 协同", intOf(sovereign.get("kernelHeat"))));
modules.add(module("kernel-engine", "Aluer Kernel", "ACTIVE",
"Threat Mesh / Echo Grid / Strain Matrix", lastPulseValue(kernel, "heat")));
modules.add(module("task-bus", "Kernel Task Bus", "QUEUE=" + taskBus.get("queuedTasks"),
"插件协议与优先级派发", intOf(taskBus.get("executedTasks"))));
modules.add(module("self-healing", "Self-Healing", String.valueOf(selfHealing.get("dryRun")),
"恢复编排与软重启护栏", intOf(selfHealing.get("cycles"))));
modules.add(module("ssh-gateway", "Remote SSH", String.valueOf(ssh.get("activeSessions")),
"远程连接、命令执行、审计联动", intOf(ssh.get("activeSessions"))));
modules.add(module("cloud-edge", "Cloud Edge", String.valueOf(cloudflareIntegrationService.getStats().get("enabled")),
"边缘挑战、Under Attack、缓存侧协同", intOf(cloudflareIntegrationService.getStats().get("blockedRequests"))));
modules.add(module("host-enforcement", "Host Enforcement", String.valueOf(hostEnforcementService.getStats().get("backend")),
"本机封禁与速率限制", intOf(hostEnforcementService.getStats().get("managedRules"))));
return modules;
}
public Map<String, Object> buildAuditFeed(int limit) {
List<Map<String, Object>> auditEvents = securityAuditService.getRecentEvents(limit).stream()
.map(event -> Map.<String, Object>of(
"category", event.getCategory(),
"player", event.getPlayer(),
"action", event.getAction(),
"details", event.getDetails(),
"timestamp", String.valueOf(event.getTimestamp())
))
.toList();
List<Map<String, Object>> networkIncidents = networkThreatFusionService.getRecentIncidents(Math.max(4, limit / 2));
List<Map<String, Object>> shieldTransitions = aluerMirageShieldService.getRecentTransitions(5).stream()
.map(AluerMirageShieldService.ShieldTransition::toMap)
.toList();
Map<String, Object> result = new LinkedHashMap<>();
result.put("events", auditEvents);
result.put("networkIncidents", networkIncidents);
result.put("shieldTransitions", shieldTransitions);
result.put("activeAlerts", securityAuditService.getActiveAlerts());
return result;
}
private Map<String, Object> module(String id, String name, String status, String summary, int signal) {
Map<String, Object> result = new LinkedHashMap<>();
result.put("id", id);
result.put("name", name);
result.put("status", status);
result.put("summary", summary);
result.put("signal", signal);
return result;
}
private int lastPulseValue(Map<String, Object> kernelStatus, String field) {
@SuppressWarnings("unchecked")
Map<String, Object> lastPulse = (Map<String, Object>) kernelStatus.get("lastPulse");
return lastPulse == null ? 0 : intOf(lastPulse.get(field));
}
private int intOf(Object value) {
if (value instanceof Number number) {
return number.intValue();
}
try {
return value == null ? 0 : Integer.parseInt(String.valueOf(value));
} catch (NumberFormatException ignored) {
return 0;
}
}
}
@@ -0,0 +1,457 @@
package com.aluer.console;
import com.aluer.audit.SecurityAuditService;
import com.aluer.config.ServerGuardConfig;
import com.aluer.security.CommandExecutionGuardService;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.HostKey;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Service
public class RemoteSshGatewayService {
private static final int CONNECT_TIMEOUT_MS = 12_000;
private static final int MAX_OUTPUT_CHARS = 16_000;
private final ServerGuardConfig config;
private final CommandExecutionGuardService commandExecutionGuardService;
private final SecurityAuditService securityAuditService;
private final AluerEngineHandshakeService aluerEngineHandshakeService;
private final Map<String, ActiveSession> sessions = new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
Thread thread = new Thread(runnable, "aluer-ssh-gateway");
thread.setDaemon(true);
return thread;
});
@Autowired
public RemoteSshGatewayService(ServerGuardConfig config,
CommandExecutionGuardService commandExecutionGuardService,
SecurityAuditService securityAuditService,
AluerEngineHandshakeService aluerEngineHandshakeService) {
this.config = config;
this.commandExecutionGuardService = commandExecutionGuardService;
this.securityAuditService = securityAuditService;
this.aluerEngineHandshakeService = aluerEngineHandshakeService;
startCleanupLoop();
}
public RemoteSshGatewayService(ServerGuardConfig config,
CommandExecutionGuardService commandExecutionGuardService,
SecurityAuditService securityAuditService) {
this(config, commandExecutionGuardService, securityAuditService, null);
}
public AluerEngineHandshakeService.HandshakeResult requestHandshake(HandshakeRequest request) {
ensureEnabled();
if (aluerEngineHandshakeService == null) {
throw new IllegalStateException("主引擎握手服务不可用");
}
return aluerEngineHandshakeService.requestSshHandshake(
new AluerEngineHandshakeService.HandshakeIntent(
request.host(),
request.port(),
request.username(),
request.purpose()
)
);
}
public SessionView connect(ConnectRequest request) {
ensureEnabled();
cleanupExpiredSessions();
if (sessions.size() >= Math.max(1, config.getDashboard().getSshGateway().getMaxSessions())) {
throw new IllegalStateException("SSH 会话已达到上限");
}
String host = requireText(request.host(), "host");
String username = requireText(request.username(), "username");
int port = request.port() > 0 ? request.port() : 22;
boolean hasPassword = request.password() != null && !request.password().isBlank();
boolean hasInlineKey = request.privateKey() != null && !request.privateKey().isBlank();
boolean hasKeyPath = request.privateKeyPath() != null && !request.privateKeyPath().isBlank();
if (!hasPassword && !hasInlineKey && !hasKeyPath) {
throw new IllegalArgumentException("请提供 SSH 密码或私钥");
}
if (hasInlineKey && !config.getDashboard().getSshGateway().isAllowPrivateKeyPaste()) {
throw new IllegalArgumentException("当前配置不允许粘贴私钥");
}
String alias = request.alias() == null || request.alias().isBlank()
? username + "@" + host
: request.alias().trim();
validateHandshake(request, host, port, username);
try {
JSch jsch = new JSch();
if (hasInlineKey) {
byte[] passphrase = toBytes(request.passphrase());
jsch.addIdentity(alias, request.privateKey().getBytes(StandardCharsets.UTF_8), null, passphrase);
} else if (hasKeyPath) {
if (request.passphrase() != null && !request.passphrase().isBlank()) {
jsch.addIdentity(request.privateKeyPath(), request.passphrase());
} else {
jsch.addIdentity(request.privateKeyPath());
}
}
Session session = jsch.getSession(username, host, port);
if (hasPassword) {
session.setPassword(request.password());
}
session.setConfig("StrictHostKeyChecking",
config.getDashboard().getSshGateway().isStrictHostKeyChecking() ? "yes" : "no");
session.connect(CONNECT_TIMEOUT_MS);
String sessionId = UUID.randomUUID().toString();
HostKey hostKey = session.getHostKey();
ActiveSession activeSession = new ActiveSession(
sessionId,
alias,
host,
port,
username,
hostKey == null ? "" : hostKey.getFingerPrint(jsch),
session
);
sessions.put(sessionId, activeSession);
securityAuditService.logEvent("SSH_GATEWAY", alias, "CONNECT", host + ":" + port);
return activeSession.toView();
} catch (JSchException e) {
throw new IllegalStateException("SSH 连接失败: " + e.getMessage(), e);
}
}
public SshCommandResult execute(String sessionId, String command) {
ensureEnabled();
ActiveSession activeSession = requireSession(sessionId);
String normalizedCommand = requireText(command, "command");
activeSession.touch();
CommandExecutionGuardService.AntiIntrusionIncident guardIncident =
commandExecutionGuardService.analyzeCommand("ssh:" + activeSession.username, normalizedCommand, activeSession.host);
ChannelExec channel = null;
long started = System.currentTimeMillis();
try {
channel = (ChannelExec) activeSession.session.openChannel("exec");
channel.setCommand(normalizedCommand);
channel.setInputStream(null);
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
channel.setOutputStream(stdout);
channel.setErrStream(stderr);
channel.connect(CONNECT_TIMEOUT_MS);
long timeoutAt = started + Math.max(5, config.getDashboard().getSshGateway().getCommandTimeoutSeconds()) * 1000L;
while (!channel.isClosed() && System.currentTimeMillis() < timeoutAt) {
Thread.sleep(120);
}
boolean timedOut = !channel.isClosed();
if (timedOut) {
channel.disconnect();
}
int exitStatus = timedOut ? -1 : channel.getExitStatus();
long durationMs = System.currentTimeMillis() - started;
String stdoutText = trimOutput(stdout.toString(StandardCharsets.UTF_8));
String stderrText = trimOutput(stderr.toString(StandardCharsets.UTF_8));
securityAuditService.logEvent(
"SSH_GATEWAY",
activeSession.alias,
"EXECUTE",
normalizedCommand + " [" + exitStatus + "]"
);
return new SshCommandResult(
sessionId,
normalizedCommand,
stdoutText,
stderrText,
exitStatus,
durationMs,
timedOut,
guardIncident != null,
guardIncident == null ? "" : guardIncident.getType(),
guardIncident == null ? 0 : guardIncident.getSeverity(),
Instant.now().toEpochMilli()
);
} catch (Exception e) {
throw new IllegalStateException("SSH 命令执行失败: " + e.getMessage(), e);
} finally {
if (channel != null && channel.isConnected()) {
channel.disconnect();
}
}
}
public SessionView disconnect(String sessionId) {
ActiveSession activeSession = requireSession(sessionId);
activeSession.session.disconnect();
sessions.remove(sessionId);
securityAuditService.logEvent("SSH_GATEWAY", activeSession.alias, "DISCONNECT", activeSession.host);
return activeSession.toView();
}
public Map<String, Object> getGatewayStatus() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("enabled", config.getDashboard().getSshGateway().isEnabled());
result.put("activeSessions", sessions.size());
result.put("sessionTimeoutMinutes", config.getDashboard().getSshGateway().getSessionTimeoutMinutes());
result.put("maxSessions", config.getDashboard().getSshGateway().getMaxSessions());
result.put("strictHostKeyChecking", config.getDashboard().getSshGateway().isStrictHostKeyChecking());
result.put("handshakeRequired", config.getDashboard().getSshGateway().isRequireEngineHandshake());
if (aluerEngineHandshakeService != null) {
result.put("engineHandshake", aluerEngineHandshakeService.getStatus());
}
result.put("sessions", listSessions());
return result;
}
public List<SessionView> listSessions() {
cleanupExpiredSessions();
return sessions.values().stream()
.sorted(Comparator.comparingLong(ActiveSession::getLastUsedAt).reversed())
.map(ActiveSession::toView)
.toList();
}
private void startCleanupLoop() {
scheduler.scheduleAtFixedRate(this::cleanupExpiredSessions, 60, 60, TimeUnit.SECONDS);
}
private void cleanupExpiredSessions() {
long cutoff = System.currentTimeMillis()
- Math.max(5, config.getDashboard().getSshGateway().getSessionTimeoutMinutes()) * 60_000L;
List<String> expired = new ArrayList<>();
for (ActiveSession activeSession : sessions.values()) {
if (activeSession.lastUsedAt < cutoff || !activeSession.session.isConnected()) {
expired.add(activeSession.sessionId);
}
}
for (String sessionId : expired) {
ActiveSession activeSession = sessions.remove(sessionId);
if (activeSession != null && activeSession.session.isConnected()) {
activeSession.session.disconnect();
}
}
}
private void ensureEnabled() {
if (!config.getDashboard().getSshGateway().isEnabled()) {
throw new IllegalStateException("SSH Gateway 已禁用");
}
}
private ActiveSession requireSession(String sessionId) {
String key = requireText(sessionId, "sessionId");
ActiveSession activeSession = sessions.get(key);
if (activeSession == null || !activeSession.session.isConnected()) {
sessions.remove(key);
throw new IllegalArgumentException("SSH 会话不存在或已断开");
}
return activeSession;
}
private String requireText(String value, String field) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException(field + " 不能为空");
}
return value.trim();
}
private void validateHandshake(ConnectRequest request, String host, int port, String username) {
if (!config.getDashboard().getSshGateway().isRequireEngineHandshake()) {
return;
}
if (aluerEngineHandshakeService == null) {
throw new IllegalStateException("主引擎握手服务不可用");
}
aluerEngineHandshakeService.consumeSshGrant(request.handshakeToken(), host, port, username);
}
private byte[] toBytes(String value) {
return value == null || value.isBlank() ? null : value.getBytes(StandardCharsets.UTF_8);
}
private String trimOutput(String value) {
if (value == null) {
return "";
}
String normalized = value.trim();
if (normalized.length() <= MAX_OUTPUT_CHARS) {
return normalized;
}
return normalized.substring(0, MAX_OUTPUT_CHARS) + "\n...[output truncated by Aluer]";
}
public record ConnectRequest(
String alias,
String host,
int port,
String username,
String password,
String privateKey,
String privateKeyPath,
String passphrase,
String handshakeToken
) {
}
public record HandshakeRequest(
String host,
int port,
String username,
String purpose
) {
}
public static class SessionView {
private final String sessionId;
private final String alias;
private final String host;
private final int port;
private final String username;
private final String fingerprint;
private final long connectedAt;
private final long lastUsedAt;
public SessionView(String sessionId,
String alias,
String host,
int port,
String username,
String fingerprint,
long connectedAt,
long lastUsedAt) {
this.sessionId = sessionId;
this.alias = alias;
this.host = host;
this.port = port;
this.username = username;
this.fingerprint = fingerprint;
this.connectedAt = connectedAt;
this.lastUsedAt = lastUsedAt;
}
public String getSessionId() { return sessionId; }
public String getAlias() { return alias; }
public String getHost() { return host; }
public int getPort() { return port; }
public String getUsername() { return username; }
public String getFingerprint() { return fingerprint; }
public long getConnectedAt() { return connectedAt; }
public long getLastUsedAt() { return lastUsedAt; }
}
public static class SshCommandResult {
private final String sessionId;
private final String command;
private final String stdout;
private final String stderr;
private final int exitStatus;
private final long durationMs;
private final boolean timedOut;
private final boolean flagged;
private final String guardType;
private final int guardSeverity;
private final long timestamp;
public SshCommandResult(String sessionId,
String command,
String stdout,
String stderr,
int exitStatus,
long durationMs,
boolean timedOut,
boolean flagged,
String guardType,
int guardSeverity,
long timestamp) {
this.sessionId = sessionId;
this.command = command;
this.stdout = stdout;
this.stderr = stderr;
this.exitStatus = exitStatus;
this.durationMs = durationMs;
this.timedOut = timedOut;
this.flagged = flagged;
this.guardType = guardType;
this.guardSeverity = guardSeverity;
this.timestamp = timestamp;
}
public String getSessionId() { return sessionId; }
public String getCommand() { return command; }
public String getStdout() { return stdout; }
public String getStderr() { return stderr; }
public int getExitStatus() { return exitStatus; }
public long getDurationMs() { return durationMs; }
public boolean isTimedOut() { return timedOut; }
public boolean isFlagged() { return flagged; }
public String getGuardType() { return guardType; }
public int getGuardSeverity() { return guardSeverity; }
public long getTimestamp() { return timestamp; }
}
private static final class ActiveSession {
private final String sessionId;
private final String alias;
private final String host;
private final int port;
private final String username;
private final String fingerprint;
private final Session session;
private final long connectedAt;
private volatile long lastUsedAt;
private ActiveSession(String sessionId,
String alias,
String host,
int port,
String username,
String fingerprint,
Session session) {
this.sessionId = sessionId;
this.alias = alias;
this.host = host;
this.port = port;
this.username = username;
this.fingerprint = fingerprint;
this.session = session;
this.connectedAt = System.currentTimeMillis();
this.lastUsedAt = this.connectedAt;
}
private long getLastUsedAt() {
return lastUsedAt;
}
private void touch() {
this.lastUsedAt = System.currentTimeMillis();
}
private SessionView toView() {
return new SessionView(sessionId, alias, host, port, username, fingerprint, connectedAt, lastUsedAt);
}
}
}