All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.mangoo.admin.AdminController Maven / Gradle / Ivy

The newest version!
package io.mangoo.admin;

import com.github.benmanes.caffeine.cache.stats.CacheStats;
import com.google.inject.Inject;
import com.google.re2j.Pattern;
import io.mangoo.annotations.FilterWith;
import io.mangoo.async.EventBus;
import io.mangoo.cache.Cache;
import io.mangoo.cache.CacheImpl;
import io.mangoo.cache.CacheProvider;
import io.mangoo.constants.*;
import io.mangoo.core.Application;
import io.mangoo.core.Config;
import io.mangoo.crypto.Crypto;
import io.mangoo.exceptions.MangooEncryptionException;
import io.mangoo.models.Metrics;
import io.mangoo.routing.Response;
import io.mangoo.routing.bindings.Form;
import io.mangoo.routing.bindings.Request;
import io.mangoo.scheduler.Scheduler;
import io.mangoo.utils.DateUtils;
import io.mangoo.utils.MangooUtils;
import io.mangoo.utils.totp.TotpUtils;
import io.undertow.server.handlers.CookieImpl;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.Strings;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.atomic.LongAdder;

import static io.mangoo.admin.AdminUtils.resetLockCounter;

@FilterWith(AdminFilter.class)
public class AdminController {
    private static final Logger LOG = LogManager.getLogger(AdminController.class);
    private static final Pattern PATTERN = Pattern.compile("[^a-zA-Z0-9]");
    private static final String ENABLED = "enabled";
    private static final String ADMIN_INDEX = "/@admin";
    private static final String PERIOD = "30";
    private static final String DIGITS = "6";
    private static final String METRICS = "metrics";
    private static final double HUNDRED_PERCENT = 100.0;
    private final CacheProvider cacheProvider;
    private final Cache cache;
    private final Config config;
    private final Crypto crypto;

    @Inject
    public AdminController(Config config, CacheProvider cacheProvider, Crypto crypto) {
        this.config = Objects.requireNonNull(config, NotNull.CONFIG);
        this.cache = cacheProvider.getCache(CacheName.APPLICATION);
        this.cacheProvider = Objects.requireNonNull(cacheProvider, NotNull.CACHE_PROVIDER);
        this.crypto = Objects.requireNonNull(crypto, NotNull.CRYPTO);
    }

    public Response index() {
        boolean enabled = config.isMetricsEnable();
        var stream = Application.getInstance(EventBus.class);

        
        if (enabled) {
            var metrics = Application.getInstance(Metrics.class);
            long totalRequests = 0;
            long errorRequests = 0;
            
            for (Entry entry :  metrics.getResponseMetrics().entrySet()) {
                if (String.valueOf(entry.getKey()).charAt(0) == '5') {
                    errorRequests = errorRequests + entry.getValue().longValue();
                }
                totalRequests = totalRequests + entry.getValue().longValue();
            }

            double errorRate = 0;
            if (errorRequests > 0) {
                errorRate = (HUNDRED_PERCENT / totalRequests) * errorRequests;
            }
            
            return Response.ok()
                    .render(ENABLED, Boolean.TRUE)
                    .render(METRICS, metrics.getResponseMetrics())
                    .render("uptime", DateUtils.getPrettyTime(Application.getStart()))
                    .render("warnings", cache.get(Key.MANGOOIO_WARNINGS))
                    .render("dataSend", MangooUtils.readableFileSize(metrics.getDataSend()))
                    .render("totalRequests", totalRequests)
                    .render("minRequestTime", metrics.getMinRequestTime())
                    .render("avgRequestTime", metrics.getAvgRequestTime())
                    .render("maxRequestTime", metrics.getMaxRequestTime())
                    .render("errorRate", errorRate)
                    .render("events", stream.getHandledEvents())
                    .render("subscribers", stream.getNumberOfSubscribers())
                    .template(Template.adminPath());
        }
        
        return Response.ok()
                .render(ENABLED, Boolean.FALSE)
                .render("uptime", DateUtils.getPrettyTime(Application.getStart()))
                .render("events", stream.getHandledEvents())
                .render("subscribers", stream.getNumberOfSubscribers())
                .render("warnings", cache.get(Key.MANGOOIO_WARNINGS))
                .template(Template.adminPath());
    }

    public Response cache() {
        Map statistics = new HashMap<>();
        for (Entry entry : cacheProvider.getCaches().entrySet()) {
            statistics.put(entry.getKey(), ((CacheImpl) entry.getValue()).getStats()); //NOSONAR
        }
        
        return Response.ok()
                .render("statistics", statistics)
                .template(Template.cachePath());
    }

    public Response scheduler() {
        Scheduler scheduler = Application.getInstance(Scheduler.class);
        return Response.ok().render("scheduler", scheduler).template(Template.schedulerPath());
    }

    public Response tools() {
        String secret = config.getApplicationAdminSecret();
        String qrCode = null;

        if (StringUtils.isBlank(secret)) {
            secret = TotpUtils.createSecret();
            qrCode = TotpUtils.getQRCode("mangoo_IO_Admin", PATTERN.matcher(config.getApplicationName()).replaceAll(""), secret, Hmac.SHA512, DIGITS, PERIOD);
        }

        return Response.ok()
                .render("qrcode", qrCode)
                .render("secret", secret)
                .template(Template.toolsPath());
    }

    public Response toolsRx(Request request) {
        Map body = request.getBodyAsJsonMap();
        Map response = new HashMap<>();

        if (body != null && !body.isEmpty()) {
            var function = body.get("function").toString();

            if (("keypair").equalsIgnoreCase(function)) {
                var keyPair = crypto.generateKeyPair();
                var publicKey = crypto.getKeyAsString(keyPair.getPublic());
                var privateKey = crypto.getKeyAsString(keyPair.getPrivate());

                response = Map.of("publickey", publicKey,  "privatekey", privateKey);
            } else if (("encrypt").equalsIgnoreCase(function)) {
                var cleartext = body.get("cleartext").toString();
                var key = body.get("key").toString();

                try {
                    var publicKey = crypto.getPublicKeyFromString(key);
                    response = Map.of("encrypted", crypto.encrypt(cleartext, publicKey));
                } catch (MangooEncryptionException e) {
                    LOG.error("Failed to encrypt cleartext.", e);
                }
            } else {
                LOG.warn("Invalid or no function selected for AJAX request.");
            }
        }

        return Response.ok().bodyJson(response);
    }
    
    public Response login() {
        return Response.ok()
                .template(Template.loginPath());
    }
    
    public Response logout() {
        var cookie = new CookieImpl(Default.ADMIN_COOKIE_NAME)
                .setValue(Strings.EMPTY)
                .setHttpOnly(true)
                .setSecure(Application.inProdMode())
                .setPath("/")
                .setDiscard(true)
                .setExpires(new Date())
                .setSameSite(true)
                .setSameSiteMode("Strict");
        
        return Response.redirect(ADMIN_INDEX).cookie(cookie);
    }
    
    public Response authenticate(Form form) {
        form.expectValue("username");
        form.expectValue("password");
        
        if (AdminUtils.isNotLocked() && form.isValid()) {
            if (AdminUtils.isValidAuthentication(form)) {
                resetLockCounter();
                return Response.redirect(ADMIN_INDEX).cookie(AdminUtils.getAdminCookie(true));
            } else {
                AdminUtils.invalidAuthentication();
            }
        }
        form.invalidate();
        form.keep();
        
        return Response.redirect("/@admin/login");
    }

    public Response verify(Form form) {
        form.expectValue("code");
        
        if (AdminUtils.isNotLocked() && form.isValid()) {
            if (TotpUtils.verifiedTotp(config.getApplicationAdminSecret(), form.get("code"))) {
                return Response.redirect(ADMIN_INDEX).cookie(AdminUtils.getAdminCookie(false));
            } else {
                AdminUtils.invalidAuthentication();
            }
        }
        form.invalidate();
        form.keep();
        
        return Response.redirect("/@admin/twofactor");
    }
    
    public Response twofactor() {
        return Response.ok().template(Template.twoFactorPath());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy