"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoginProvider = exports.samlauthstrategyoptions = exports.googleauthstrategyoptions = exports.Provider = void 0;
const url = require("url");
const express = require("express");
const path = require("path");
const OpenIDConnectStrategy = require("passport-openidconnect");
const GoogleStrategy = require("passport-google-oauth20");
const LocalStrategy = require("passport-local");
const passport = require("passport");
const Config_1 = require("./Config");
const Crypt_1 = require("./Crypt");
const Audit_1 = require("./Audit");
const saml = require("saml20");
const mongodb_1 = require("mongodb");
const openflow_api_1 = require("@openiap/openflow-api");
const Logger_1 = require("./Logger");
const DatabaseConnection_1 = require("./DatabaseConnection");
var nodemailer = require('nodemailer');
var dns = require('dns');
const got = require("got");
const safeObjectID = (s) => mongodb_1.ObjectId.isValid(s) ? new mongodb_1.ObjectId(s) : null;
class Provider extends openflow_api_1.Base {
    constructor() {
        super();
        this.provider = "";
        this.id = "";
        this.name = "";
        this.issuer = "";
        this.saml_federation_metadata = "";
        this._type = "provider";
    }
}
exports.Provider = Provider;
// tslint:disable-next-line: class-name
class googleauthstrategyoptions {
    constructor() {
        this.clientID = "";
        this.clientSecret = "";
        this.callbackURL = "auth/strategy/callback/";
        this.scope = ["profile", "email"];
    }
}
exports.googleauthstrategyoptions = googleauthstrategyoptions;
// tslint:disable-next-line: class-name
class samlauthstrategyoptions {
    constructor() {
        this.callbackUrl = "auth/strategy/callback/";
        this.entryPoint = "";
        this.issuer = "";
        this.cert = null;
        this.audience = null;
        this.signatureAlgorithm = "sha256";
        this.callbackMethod = "POST";
    }
}
exports.samlauthstrategyoptions = samlauthstrategyoptions;
class LoginProvider {
    // public static login_providers: Provider[] = [];
    static remoteip(req) {
        let remoteip = req.socket.remoteAddress;
        if (req.headers["X-Forwarded-For"] != null)
            remoteip = req.headers["X-Forwarded-For"];
        if (req.headers["X-real-IP"] != null)
            remoteip = req.headers["X-real-IP"];
        if (req.headers["x-forwarded-for"] != null)
            remoteip = req.headers["x-forwarded-for"];
        if (req.headers["x-real-ip"] != null)
            remoteip = req.headers["x-real-ip"];
        return remoteip;
    }
    static escape(s) {
        let lookup = {
            '&': "&amp;",
            '"': "&quot;",
            '<': "&lt;",
            '>': "&gt;"
        };
        return s.replace(/[&"<>]/g, (c) => lookup[c]);
    }
    static redirect(res, originalUrl) {
        res.write('<!DOCTYPE html>');
        res.write('<body>');
        res.write('<script>top.location = "' + LoginProvider.escape(originalUrl) + '";</script>');
        res.write('</body>');
        res.write('</html>');
        res.end();
    }
    static async validateToken(rawAssertion, parent) {
        const span = Logger_1.Logger.otel.startSubSpan("LoginProvider.validateToken", parent);
        return new Promise((resolve, reject) => {
            try {
                const options = {
                    publicKey: Buffer.from(Config_1.Config.signing_crt, "base64").toString("ascii")
                };
                Logger_1.Logger.instanse.verbose("saml.validate", span);
                saml.validate(rawAssertion, options, async (err, profile) => {
                    const span = Logger_1.Logger.otel.startSpan("saml.validate", null, null);
                    try {
                        if (err) {
                            Logger_1.Logger.instanse.error(err, span);
                            return reject(err);
                        }
                        const claims = profile.claims; // Array of user attributes;
                        const username = claims["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"] ||
                            claims["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"] ||
                            claims["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"];
                        Logger_1.Logger.instanse.verbose("lookup " + username, span);
                        const user = await Logger_1.Logger.DBHelper.FindByUsername(username, null, span);
                        if (user) {
                            Logger_1.Logger.instanse.debug("succesfull", span);
                            resolve(user);
                        }
                        else {
                            Logger_1.Logger.instanse.error(new Error("Unknown user"), span);
                            reject("Unknown user");
                        }
                    }
                    catch (error) {
                        Logger_1.Logger.instanse.error(error, span);
                        reject(error);
                    }
                    finally {
                        Logger_1.Logger.otel.endSpan(span);
                    }
                });
            }
            catch (error) {
                Logger_1.Logger.instanse.error(error, span);
            }
            finally {
                Logger_1.Logger.otel.endSpan(span);
            }
        });
    }
    static async configure(app, baseurl, parent) {
        app.use(passport.initialize());
        app.use(passport.session());
        passport.serializeUser(async function (user, done) {
            const tuser = openflow_api_1.TokenUser.From(user);
            // await Auth.AddUser(tuser as any, tuser._id, "passport");
            done(null, user._id);
        });
        passport.deserializeUser(async function (userid, done) {
            Logger_1.Logger.instanse.silly("userid " + userid, null);
            if (openflow_api_1.NoderedUtil.IsNullEmpty(userid))
                return done('missing userid', null);
            if (typeof userid !== 'string')
                userid = userid._id;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(userid))
                return done('missing userid', null);
            const _user = await Logger_1.Logger.DBHelper.FindById(userid, null);
            if (_user == null) {
                Logger_1.Logger.instanse.error("Failed locating user " + userid, null);
                done(null, null);
            }
            else {
                Logger_1.Logger.instanse.verbose("found user " + userid + " " + _user.name, null);
                done(null, _user);
            }
            // const _user = await Auth.getUser(userid, "passport");
            // if (_user == null) {
            //     const user = await DBHelper.FindById(userid, null, null);
            //     if (user != null) {
            //         const tuser = TokenUser.From(user);
            //         await Auth.AddUser(tuser as any, tuser._id, "passport");
            //         done(null, tuser);
            //     } else {
            //         done(null, null);
            //     }
            // } else {
            //     done(null, _user);
            // }
        });
        app.get("/dashboardauth", LoginProvider.get_dashboardauth.bind(this));
        app.get("/Signout", LoginProvider.get_Signout.bind(this));
        app.get("/PassiveSignout", LoginProvider.get_PassiveSignout.bind(this));
        await LoginProvider.RegisterProviders(app, baseurl, parent);
        app.get("/user", LoginProvider.get_user.bind(this));
        app.get("/jwt", LoginProvider.get_jwt.bind(this));
        app.get("/jwtlong", LoginProvider.get_jwtlong.bind(this));
        app.post("/jwt", LoginProvider.post_jwt.bind(this));
        app.get("/config", LoginProvider.get_config.bind(this));
        app.post("/AddTokenRequest", LoginProvider.post_AddTokenRequest.bind(this));
        app.get("/GetTokenRequest", LoginProvider.get_GetTokenRequest.bind(this));
        app.get("/login", LoginProvider.get_login.bind(this));
        app.get("/validateuserform", LoginProvider.get_validateuserform.bind(this));
        app.get("/read/:id", LoginProvider.get_read.bind(this));
        app.post("/validateuserform", LoginProvider.post_validateuserform.bind(this));
        app.post("/forgotpassword", LoginProvider.post_forgotpassword.bind(this));
        app.get("/loginproviders", LoginProvider.get_loginproviders.bind(this));
        app.get("/download/:id", LoginProvider.get_download.bind(this));
    }
    static async RegisterProviders(app, baseurl, parent) {
        const span = Logger_1.Logger.otel.startSubSpan("LoginProvider.RegisterProviders", parent);
        try {
            let hasLocal = false;
            var providers = await Logger_1.Logger.DBHelper.GetProviders(span);
            if (providers.length === 0) {
                hasLocal = true;
            }
            providers.forEach(async (provider) => {
                try {
                    if (openflow_api_1.NoderedUtil.IsNullUndefinded(LoginProvider._providers[provider.id])) {
                        if (provider.provider === "saml") {
                            const metadata = await Config_1.Config.parse_federation_metadata(provider.saml_federation_metadata);
                            LoginProvider._providers[provider.id] =
                                LoginProvider.CreateSAMLStrategy(app, provider.id, metadata.cert, metadata.identityProviderUrl, provider.issuer, baseurl, span);
                        }
                        if (provider.provider === "google") {
                            LoginProvider._providers[provider.id] =
                                LoginProvider.CreateGoogleStrategy(app, provider.id, provider.consumerKey, provider.consumerSecret, baseurl, span);
                        }
                        if (provider.provider === "oidc") {
                            await LoginProvider.CreateOpenIDStrategy(app, provider.saml_federation_metadata, provider.id, provider.consumerKey, provider.consumerSecret, baseurl, span);
                        }
                    }
                    if (provider.provider === "local") {
                        hasLocal = true;
                    }
                }
                catch (error) {
                    Logger_1.Logger.instanse.error(error, span);
                }
            });
            if (hasLocal === true) {
                if (openflow_api_1.NoderedUtil.IsNullUndefinded(LoginProvider._providers.local)) {
                    LoginProvider._providers.local = LoginProvider.CreateLocalStrategy(app, baseurl);
                }
            }
            const keys = Object.keys(LoginProvider._providers);
            for (var i = 0; i < keys.length; i++) {
                let key = keys[i];
                var exists = providers.filter(x => x.id == key || (key == 'local' && x.provider == 'local'));
                if (exists.length == 0) {
                    Logger_1.Logger.instanse.debug("[loginprovider] Removing passport strategy " + key, span);
                    passport.unuse(key);
                }
            }
        }
        catch (error) {
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    // https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
    // https://login.microsoftonline.com/aa8306d8-5417-43cc-b8e8-7e77b918682c/v2.0/.well-known/openid-configuration
    // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc
    // common - Users with both a personal Microsoft account and a work or school account from Azure AD can sign in to the application.
    // organizations - Only users with work or school accounts from Azure AD can sign in to the application
    // consumers - Only users with a personal Microsoft account can sign in to the application
    // aa8306d8-5417-43cc-b8e8-7e77b918682c - Only users from a specific Azure AD tenant
    // 9188040d-6c67-4c5b-b112-36a304b66dad = consumers tenant
    // https://login.microsoftonline.com/consumers/v2.0/.well-known/openid-configuration
    static async CreateOpenIDStrategy(app, discoveryurl, key, clientID, clientSecret, baseurl, span) {
        Logger_1.Logger.instanse.debug("Adding new google strategy " + key, span);
        const response = await got.get(discoveryurl, options);
        const document = JSON.parse(response.body);
        var options = {
            issuer: document.issuer,
            authorizationURL: document.authorization_endpoint,
            tokenURL: document.token_endpoint,
            userInfoURL: document.userinfo_endpoint,
            clientID: clientID,
            clientSecret: clientSecret,
            callbackURL: url.parse(baseurl).protocol + "//" + url.parse(baseurl).host + "/" + key + "/",
            verify: (LoginProvider.openidverify).bind(this),
            scope: "email profile"
        };
        // Microsoft Graph: openid, email, profile, and offline_access. The address and phone. OpenID Connect scopes aren't supported
        // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent
        const strategy = new OpenIDConnectStrategy.Strategy(options, options.verify);
        passport.use(key, strategy);
        strategy.name = key;
        app.use("/" + key, express.urlencoded({ extended: false }), passport.authenticate(key, { failureRedirect: "/" + key, failureFlash: true }), function (req, res) {
            const span = Logger_1.Logger.otel.startSpanExpress("OpenIDStrategy", req);
            try {
                const originalUrl = req.cookies.originalUrl;
                res.cookie("provider", key, { maxAge: 900000, httpOnly: true });
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl)) {
                    res.cookie("originalUrl", "", { expires: new Date(0) });
                    LoginProvider.redirect(res, originalUrl);
                }
                else {
                    res.redirect("/");
                }
            }
            catch (error) {
                Logger_1.Logger.instanse.error(error, span);
                return res.status(500).send({ message: error.message ? error.message : error });
            }
            finally {
                Logger_1.Logger.otel.endSpan(span);
            }
        });
        return strategy;
    }
    static CreateGoogleStrategy(app, key, consumerKey, consumerSecret, baseurl, span) {
        Logger_1.Logger.instanse.debug("Adding new google strategy " + key, span);
        const options = new googleauthstrategyoptions();
        options.clientID = consumerKey;
        options.clientSecret = consumerSecret;
        options.callbackURL = url.parse(baseurl).protocol + "//" + url.parse(baseurl).host + "/" + key + "/";
        options.passReqToCallback = true;
        options.verify = (LoginProvider.googleverify).bind(this);
        const strategy = new GoogleStrategy.Strategy(options, options.verify);
        passport.use(key, strategy);
        strategy.name = key;
        app.use("/" + key, express.urlencoded({ extended: false }), passport.authenticate(key, { failureRedirect: "/" + key, failureFlash: true }), function (req, res) {
            const span = Logger_1.Logger.otel.startSpanExpress("GoogleStrategy", req);
            try {
                const originalUrl = req.cookies.originalUrl;
                res.cookie("provider", key, { maxAge: 900000, httpOnly: true });
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl)) {
                    res.cookie("originalUrl", "", { expires: new Date(0) });
                    LoginProvider.redirect(res, originalUrl);
                }
                else {
                    res.redirect("/");
                }
            }
            catch (error) {
                Logger_1.Logger.instanse.error(error, span);
                return res.status(500).send({ message: error.message ? error.message : error });
            }
            finally {
                Logger_1.Logger.otel.endSpan(span);
            }
        });
        return strategy;
    }
    // tslint:disable-next-line: max-line-length
    static CreateSAMLStrategy(app, key, cert, singin_url, issuer, baseurl, span) {
        Logger_1.Logger.instanse.debug("Adding new SAML strategy " + key, span);
        const options = new samlauthstrategyoptions();
        options.passReqToCallback = true;
        options.entryPoint = singin_url;
        options.cert = cert;
        options.issuer = issuer;
        options.callbackUrl = url.parse(baseurl).protocol + "//" + url.parse(baseurl).host + "/" + key + "/";
        options.verify = (LoginProvider.samlverify).bind(this);
        const SamlStrategy = require('passport-saml').Strategy;
        const strategy = new SamlStrategy(options, options.verify);
        passport.use(key, strategy);
        strategy.name = key;
        // app.get("/" + key + "/FederationMetadata/2007-06/FederationMetadata.xml",
        //     wsfed.metadata({
        //         cert: Buffer.from(Config.signing_crt, "base64").toString("ascii"),
        //         issuer: issuer
        //     }));
        const CertPEM = Buffer.from(Config_1.Config.signing_crt, "base64").toString("ascii").replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, '');
        app.get("/" + key + "/FederationMetadata/2007-06/FederationMetadata.xml", (req, res, next) => {
            const span = Logger_1.Logger.otel.startSpanExpress("FederationMetadata", req);
            try {
                res.set("Content-Type", "text/xml");
                res.send(`
                        <EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="` + issuer + `">
                        <RoleDescriptor xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706" xsi:type="fed:SecurityTokenServiceType" protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706" 
                        ServiceDisplayName="` + issuer + `">
                        <KeyDescriptor use="signing">
                        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                        <X509Data>
                        <X509Certificate>` + CertPEM + `</X509Certificate>
                        </X509Data>
                        </KeyInfo>
                        </KeyDescriptor>
                        <fed:TokenTypesOffered>
                        <fed:TokenType Uri="urn:oasis:names:tc:SAML:2.0:assertion"/>
                        <fed:TokenType Uri="urn:oasis:names:tc:SAML:1.0:assertion"/>
                        </fed:TokenTypesOffered>
                        <fed:ClaimTypesOffered>
                        <auth:ClaimType xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706" Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" Optional="true">
                        <auth:DisplayName>E-Mail Address</auth:DisplayName>
                        <auth:Description>The e-mail address of the user</auth:Description>
                        </auth:ClaimType>
                        <auth:ClaimType xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706" Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" Optional="true">
                        <auth:DisplayName>Given Name</auth:DisplayName>
                        <auth:Description>The given name of the user</auth:Description>
                        </auth:ClaimType>
                        <auth:ClaimType xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706" Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" Optional="true">
                        <auth:DisplayName>Name</auth:DisplayName>
                        <auth:Description>The unique name of the user</auth:Description>
                        </auth:ClaimType>
                        <auth:ClaimType xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706" Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" Optional="true">
                        <auth:DisplayName>Surname</auth:DisplayName>
                        <auth:Description>The surname of the user</auth:Description>
                        </auth:ClaimType>
                        <auth:ClaimType xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706" Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" Optional="true">
                        <auth:DisplayName>Name ID</auth:DisplayName>
                        <auth:Description>The SAML name identifier of the user</auth:Description>
                        </auth:ClaimType>
                        </fed:ClaimTypesOffered>originalUrl
                        <fed:PassiveRequestorEndpoint>
                        <EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
                        <Address>` + options.callbackUrl + `</Address>
                        </EndpointReference>
                        </fed:PassiveRequestorEndpoint>
                        </RoleDescriptor>
                        </EntityDescriptor>
                        `);
            }
            catch (error) {
                Logger_1.Logger.instanse.error(error, span);
                return res.status(500).send({ message: error.message ? error.message : error });
            }
            finally {
                Logger_1.Logger.otel.endSpan(span);
            }
        });
        app.use("/" + key, express.urlencoded({ extended: false }), passport.authenticate(key, { failureRedirect: "/" + key, failureFlash: true }), function (req, res) {
            const span = Logger_1.Logger.otel.startSpanExpress("SAML" + key, req);
            try {
                const originalUrl = req.cookies.originalUrl;
                res.cookie("provider", key, { maxAge: 900000, httpOnly: true });
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl)) {
                    res.cookie("originalUrl", "", { expires: new Date(0) });
                    LoginProvider.redirect(res, originalUrl);
                }
                else {
                    res.redirect("/");
                }
            }
            catch (error) {
                Logger_1.Logger.instanse.error(error, span);
                return res.status(500).send({ message: error.message ? error.message : error });
            }
            finally {
                Logger_1.Logger.otel.endSpan(span);
            }
        });
        return strategy;
    }
    static CreateLocalStrategy(app, baseurl) {
        const strategy = new LocalStrategy({ passReqToCallback: true }, async (req, username, password, done) => {
            const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.LocalLogin", req);
            Logger_1.Logger.instanse.debug("Adding new local strategy", span);
            try {
                let remoteip = "";
                if (!openflow_api_1.NoderedUtil.IsNullUndefinded(req)) {
                    remoteip = LoginProvider.remoteip(req);
                }
                span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", remoteip);
                if (username !== null && username != undefined) {
                    username = username.toLowerCase();
                }
                let user = null;
                var providers = await Logger_1.Logger.DBHelper.GetProviders(span);
                if (providers.length === 0 || openflow_api_1.NoderedUtil.IsNullEmpty(providers[0]._id)) {
                    user = await Logger_1.Logger.DBHelper.FindByUsername(username, null, span);
                    if (user == null) {
                        Logger_1.Logger.instanse.info("No login providers, creating " + username + " as admin", span);
                        user = new openflow_api_1.User();
                        user.name = username;
                        user.username = username;
                        await Crypt_1.Crypt.SetPassword(user, password, span);
                        const jwt = Crypt_1.Crypt.rootToken();
                        user = await Logger_1.Logger.DBHelper.EnsureUser(jwt, user.name, user.username, null, password, null, span);
                        const admins = await Logger_1.Logger.DBHelper.FindRoleByName("admins", null, span);
                        if (admins == null)
                            throw new Error("Failed locating admins role!");
                        admins.AddMember(user);
                        await Logger_1.Logger.DBHelper.Save(admins, Crypt_1.Crypt.rootToken(), span);
                    }
                    else {
                        if (!(await Crypt_1.Crypt.ValidatePassword(user, password, span))) {
                            Logger_1.Logger.instanse.error("No login providers, login for " + username + " failed", span);
                            await Audit_1.Audit.LoginFailed(username, "weblogin", "local", remoteip, "browser", "unknown", span);
                            return done(null, false);
                        }
                        Logger_1.Logger.instanse.info("No login providers, updating " + username + " as admin", span);
                        const admins = await Logger_1.Logger.DBHelper.FindRoleByName("admins", null, span);
                        if (admins == null)
                            throw new Error("Failed locating admins role!");
                        admins.AddMember(user);
                        await Logger_1.Logger.DBHelper.Save(admins, Crypt_1.Crypt.rootToken(), span);
                    }
                    Logger_1.Logger.instanse.info("Clear cache", span);
                    await Logger_1.Logger.DBHelper.clearCache("Initialized", span);
                    await Audit_1.Audit.LoginSuccess(openflow_api_1.TokenUser.From(user), "weblogin", "local", remoteip, "browser", "unknown", span);
                    const provider = new Provider();
                    provider.provider = "local";
                    provider.name = "Local";
                    Logger_1.Logger.instanse.info("Saving local provider", span);
                    const result = await Config_1.Config.db.InsertOne(provider, "config", 0, false, Crypt_1.Crypt.rootToken(), span);
                    Logger_1.Logger.instanse.info("local provider created as " + result._id, span);
                    await Logger_1.Logger.DBHelper.ClearProviders();
                    const tuser = openflow_api_1.TokenUser.From(user);
                    done(null, tuser);
                    if (Logger_1.Logger.License.validlicense) {
                        var model = new openflow_api_1.Base();
                        model._type = "oauthclient";
                        model.name = "grafana";
                        model._encrypt = ["clientSecret"];
                        model.clientId = "application";
                        model.clientSecret = 'secret';
                        model.grants = ['password', 'refresh_token', 'authorization_code'];
                        model.redirectUris = [];
                        model.defaultrole = "Viewer";
                        model.rolemappings = { "admins": "Admin", "grafana editors": "Editor", "grafana admins": "Admin" };
                        // (model as any).token_endpoint_auth_method = "none";
                        model.token_endpoint_auth_method = "client_secret_post";
                        model.response_types = ['code', 'id_token', 'code id_token'];
                        model.grant_types = ['implicit', 'authorization_code'];
                        model.post_logout_redirect_uris = [];
                        await Config_1.Config.db.InsertOne(model, "config", 0, false, Crypt_1.Crypt.rootToken(), span);
                    }
                    return;
                }
                user = await Logger_1.Logger.DBHelper.FindByUsername(username, null, span);
                if (openflow_api_1.NoderedUtil.IsNullUndefinded(user)) {
                    let createUser = Config_1.Config.auto_create_users;
                    if (!createUser) {
                        return done(null, false);
                    }
                    user = await Logger_1.Logger.DBHelper.EnsureUser(Crypt_1.Crypt.rootToken(), username, username, null, password, null, span);
                }
                else {
                    if (user.disabled) {
                        await Audit_1.Audit.LoginFailed(username, "weblogin", "local", remoteip, "browser", "unknown", span);
                        done("Disabled user " + username, null);
                        return;
                    }
                    if (!(await Crypt_1.Crypt.ValidatePassword(user, password, span))) {
                        await Audit_1.Audit.LoginFailed(username, "weblogin", "local", remoteip, "browser", "unknown", span);
                        return done(null, false);
                    }
                }
                const tuser = openflow_api_1.TokenUser.From(user);
                await Audit_1.Audit.LoginSuccess(tuser, "weblogin", "local", remoteip, "browser", "unknown", span);
                // tuser.roles.splice(40, tuser.roles.length)
                Logger_1.Logger.otel.endSpan(span);
                return done(null, tuser);
            }
            catch (error) {
                Logger_1.Logger.instanse.error(error, span);
                Logger_1.Logger.otel.endSpan(span);
                done(error.message ? error.message : error);
            }
        });
        passport.use("local", strategy);
        app.use("/local", express.urlencoded({ extended: false }), async (req, res, next) => {
            var _a;
            const username = (_a = req.body) === null || _a === void 0 ? void 0 : _a.username;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(username) && username.indexOf("@") > -1) {
                const domain = username.substr(username.indexOf("@") + 1);
                var providers = await Logger_1.Logger.DBHelper.GetProviders(null);
                for (let i = 0; i < providers.length; i++) {
                    var provider = providers[i];
                    if (provider.forceddomains && Array.isArray(provider.forceddomains)) {
                        for (let d = 0; d < provider.forceddomains.length; d++) {
                            let forceddomain = new RegExp(provider.forceddomains[d], "i");
                            if (forceddomain.test(domain)) {
                                res.redirect("/" + providers[i].id);
                                return next();
                            }
                        }
                    }
                }
            }
            passport.authenticate("local", function (err, user, info) {
                let originalUrl = req.cookies.originalUrl;
                if (err) {
                    Logger_1.Logger.instanse.error(err, null);
                }
                if (!err && user) {
                    req.logIn(user, function (err) {
                        if (err) {
                            Logger_1.Logger.instanse.debug("req.logIn failed", null);
                            Logger_1.Logger.instanse.error(err, null);
                            return next(err);
                        }
                        if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.validate_user_form) && req.user.validated == false) {
                            res.redirect("/login");
                            return next();
                        }
                        else if (!openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl)) {
                            try {
                                res.cookie("originalUrl", "", { expires: new Date(0) });
                                LoginProvider.redirect(res, originalUrl);
                                Logger_1.Logger.instanse.debug("redirect: " + originalUrl, null);
                                return;
                            }
                            catch (error) {
                                Logger_1.Logger.instanse.error(error, null);
                            }
                        }
                        else {
                            res.redirect("/");
                            return next();
                        }
                    });
                    return;
                }
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl)) {
                    if (originalUrl.indexOf("?") == -1) {
                        originalUrl = originalUrl + "?error=1";
                    }
                    else if (originalUrl.indexOf("error=1") == -1) {
                        originalUrl = originalUrl + "&error=1";
                    }
                    try {
                        res.cookie("originalUrl", "", { expires: new Date(0) });
                        Logger_1.Logger.instanse.debug("redirect: " + originalUrl, null);
                        LoginProvider.redirect(res, originalUrl);
                    }
                    catch (error) {
                        Logger_1.Logger.instanse.error(error, null);
                    }
                }
                else {
                    try {
                        res.redirect("/");
                        return next();
                    }
                    catch (error) {
                        Logger_1.Logger.instanse.error(error, null);
                    }
                }
            })(req, res, next);
        });
        return strategy;
    }
    static async samlverify(req, profile, done) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.samlverify", req);
        try {
            const issuer = req.baseUrl.replace("/", "");
            let username = profile.username;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(username))
                username = profile.nameID;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(username)) {
                username = username.toLowerCase();
            }
            Logger_1.Logger.instanse.debug(username, span);
            let _user = await Logger_1.Logger.DBHelper.FindByUsernameOrFederationid(username, issuer, span);
            let remoteip = "";
            if (!openflow_api_1.NoderedUtil.IsNullUndefinded(req)) {
                remoteip = LoginProvider.remoteip(req);
            }
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", remoteip);
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(_user)) {
                let createUser = Config_1.Config.auto_create_users;
                if (Config_1.Config.auto_create_domains.map(x => username.endsWith(x)).length > 0) {
                    createUser = true;
                }
                if (createUser) {
                    _user = new openflow_api_1.User();
                    _user.name = profile.name;
                    if (!openflow_api_1.NoderedUtil.IsNullEmpty(profile["http://schemas.microsoft.com/identity/claims/displayname"])) {
                        _user.name = profile["http://schemas.microsoft.com/identity/claims/displayname"];
                    }
                    if (!openflow_api_1.NoderedUtil.IsNullEmpty(profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"])) {
                        _user.name = profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"];
                    }
                    _user.username = username;
                    if (!openflow_api_1.NoderedUtil.IsNullEmpty(profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobile"])) {
                        _user.mobile = profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobile"];
                    }
                    if (openflow_api_1.NoderedUtil.IsNullEmpty(_user.name)) {
                        done("Cannot add new user, name is empty, please add displayname to claims", null);
                        return;
                    }
                    const jwt = Crypt_1.Crypt.rootToken();
                    let extraoptions = {
                        federationids: [new openflow_api_1.FederationId(username, issuer)],
                        emailvalidated: true
                    };
                    _user = await Logger_1.Logger.DBHelper.EnsureUser(jwt, _user.name, _user.username, null, null, extraoptions, span);
                }
            }
            else {
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobile"])) {
                    _user.mobile = profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobile"];
                }
                var exists = _user.federationids.filter(x => x.id == username && x.issuer == issuer);
                if (exists.length == 0) {
                    _user.federationids = _user.federationids.filter(x => x.issuer != issuer);
                    _user.federationids.push(new openflow_api_1.FederationId(username, issuer));
                }
                _user.emailvalidated = true;
                if (_user.formvalidated)
                    _user.validated = true;
                const jwt = Crypt_1.Crypt.rootToken();
                await Logger_1.Logger.DBHelper.Save(_user, jwt, span);
                await Logger_1.Logger.DBHelper.UserRoleUpdate(_user, false, span);
            }
            if (!openflow_api_1.NoderedUtil.IsNullUndefinded(_user)) {
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(profile["http://schemas.xmlsoap.org/claims/Group"])) {
                    const jwt = Crypt_1.Crypt.rootToken();
                    const strroles = profile["http://schemas.xmlsoap.org/claims/Group"];
                    for (let i = 0; i < strroles.length; i++) {
                        const role = await Logger_1.Logger.DBHelper.FindRoleByName(strroles[i], jwt, span);
                        if (!openflow_api_1.NoderedUtil.IsNullUndefinded(role)) {
                            role.AddMember(_user);
                            await Logger_1.Logger.DBHelper.Save(role, jwt, span);
                        }
                    }
                    _user = await Logger_1.Logger.DBHelper.DecorateWithRoles(_user, span);
                }
            }
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(_user)) {
                await Audit_1.Audit.LoginFailed(username, "weblogin", "saml", remoteip, "samlverify", "unknown", span);
                done("unknown user " + username, null);
                return;
            }
            if (_user.disabled) {
                await Audit_1.Audit.LoginFailed(username, "weblogin", "saml", remoteip, "samlverify", "unknown", span);
                done("Disabled user " + username, null);
                return;
            }
            const tuser = openflow_api_1.TokenUser.From(_user);
            await Audit_1.Audit.LoginSuccess(tuser, "weblogin", "saml", remoteip, "samlverify", "unknown", span);
            Logger_1.Logger.otel.endSpan(span);
            done(null, tuser);
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
        }
        Logger_1.Logger.otel.endSpan(span);
    }
    static async openidverify(issuer, profile, done) {
        const span = Logger_1.Logger.otel.startSpan("LoginProvider.openidverify", null, null);
        const remoteip = "unknown";
        try {
            if (profile.id && !profile.username)
                profile.username = profile.id;
            if (profile.emails) {
                const email = profile.emails[0];
                profile.username = email.value;
            }
            let username = profile.username;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(username))
                username = profile.nameID;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(username)) {
                username = username.toLowerCase();
            }
            Logger_1.Logger.instanse.debug(profile.id, span);
            let _user = await Logger_1.Logger.DBHelper.FindByUsernameOrFederationid(profile.id, issuer, span);
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(_user)) {
                _user = await Logger_1.Logger.DBHelper.FindByUsernameOrFederationid(profile.username, issuer, span);
            }
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(_user)) {
                let createUser = Config_1.Config.auto_create_users;
                if (Config_1.Config.auto_create_domains.map(x => username.endsWith(x)).length > 0) {
                    createUser = true;
                }
                if (createUser) {
                    const jwt = Crypt_1.Crypt.rootToken();
                    _user = new openflow_api_1.User();
                    _user.name = profile.name;
                    if (!openflow_api_1.NoderedUtil.IsNullEmpty(profile.displayName)) {
                        _user.name = profile.displayName;
                    }
                    _user.username = username;
                    _user.mobile = profile.mobile;
                    // if (NoderedUtil.IsNullEmpty(_user.name)) { done("Cannot add new user, name is empty.", null); return; }
                    if (openflow_api_1.NoderedUtil.IsNullEmpty(_user.name))
                        _user.name = username;
                    let extraoptions = {
                        federationids: [new openflow_api_1.FederationId(profile.id, issuer)],
                        emailvalidated: true
                    };
                    // ,emailvalidated: true
                    _user = await Logger_1.Logger.DBHelper.EnsureUser(jwt, _user.name, _user.username, null, null, extraoptions, span);
                }
            }
            else {
                var exists = _user.federationids.filter(x => x.id == profile.id && x.issuer == issuer);
                if (exists.length == 0 || _user.emailvalidated == false) {
                    _user.federationids = _user.federationids.filter(x => x.issuer != issuer);
                    _user.federationids.push(new openflow_api_1.FederationId(profile.id, issuer));
                    _user.emailvalidated = true;
                    if (_user.formvalidated)
                        _user.validated = true;
                    const jwt = Crypt_1.Crypt.rootToken();
                    await Logger_1.Logger.DBHelper.Save(_user, jwt, span);
                    await Logger_1.Logger.DBHelper.UserRoleUpdate(_user, false, span);
                }
            }
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(_user)) {
                await Audit_1.Audit.LoginFailed(username, "weblogin", "openid", remoteip, "openidverify", "unknown", span);
                done("unknown user " + username, null);
                return;
            }
            if (_user.disabled) {
                await Audit_1.Audit.LoginFailed(username, "weblogin", "openid", remoteip, "openidverify", "unknown", span);
                done("Disabled user " + username, null);
                return;
            }
            const tuser = openflow_api_1.TokenUser.From(_user);
            await Audit_1.Audit.LoginSuccess(tuser, "weblogin", "openid", remoteip, "openidverify", "unknown", span);
            done(null, tuser);
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
        }
        Logger_1.Logger.otel.endSpan(span);
    }
    static async googleverify(req, token, tokenSecret, profile, done) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.googleverify", req);
        try {
            if (profile.emails) {
                const email = profile.emails[0];
                profile.username = email.value;
            }
            let remoteip = "";
            if (!openflow_api_1.NoderedUtil.IsNullUndefinded(req)) {
                remoteip = LoginProvider.remoteip(req);
            }
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", remoteip);
            const issuer = req.baseUrl.replace("/", "");
            let username = profile.username;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(username))
                username = profile.nameID;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(username)) {
                username = username.toLowerCase();
            }
            Logger_1.Logger.instanse.debug(username, span);
            let _user = await Logger_1.Logger.DBHelper.FindByUsernameOrFederationid(username, issuer, span);
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(_user)) {
                let createUser = Config_1.Config.auto_create_users;
                if (Config_1.Config.auto_create_domains.map(x => username.endsWith(x)).length > 0) {
                    createUser = true;
                }
                if (createUser) {
                    const jwt = Crypt_1.Crypt.rootToken();
                    _user = new openflow_api_1.User();
                    _user.name = profile.name;
                    if (!openflow_api_1.NoderedUtil.IsNullEmpty(profile.displayName)) {
                        _user.name = profile.displayName;
                    }
                    _user.username = username;
                    _user.mobile = profile.mobile;
                    if (openflow_api_1.NoderedUtil.IsNullEmpty(_user.name)) {
                        done("Cannot add new user, name is empty.", null);
                        return;
                    }
                    let extraoptions = {
                        federationids: [new openflow_api_1.FederationId(username, issuer)],
                        emailvalidated: true
                    };
                    _user = await Logger_1.Logger.DBHelper.EnsureUser(jwt, _user.name, _user.username, null, null, extraoptions, span);
                }
            }
            else {
                var exists = _user.federationids.filter(x => x.id == username && x.issuer == issuer);
                if (exists.length == 0 || _user.emailvalidated == false) {
                    _user.federationids = _user.federationids.filter(x => x.issuer != issuer);
                    _user.federationids.push(new openflow_api_1.FederationId(username, issuer));
                    _user.emailvalidated = true;
                    if (_user.formvalidated)
                        _user.validated = true;
                    const jwt = Crypt_1.Crypt.rootToken();
                    await Logger_1.Logger.DBHelper.Save(_user, jwt, span);
                    await Logger_1.Logger.DBHelper.UserRoleUpdate(_user, false, span);
                }
            }
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(_user)) {
                await Audit_1.Audit.LoginFailed(username, "weblogin", "google", remoteip, "googleverify", "unknown", span);
                done("unknown user " + username, null);
                return;
            }
            if (_user.disabled) {
                await Audit_1.Audit.LoginFailed(username, "weblogin", "google", remoteip, "googleverify", "unknown", span);
                done("Disabled user " + username, null);
                return;
            }
            const tuser = openflow_api_1.TokenUser.From(_user);
            await Audit_1.Audit.LoginSuccess(tuser, "weblogin", "google", remoteip, "googleverify", "unknown", span);
            done(null, tuser);
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
        }
        Logger_1.Logger.otel.endSpan(span);
    }
    static reverseLookup(ip) {
        return new Promise((resolve, reject) => {
            dns.reverse(ip, function (err, domains) {
                if (err != null)
                    return reject(err);
                domains.forEach(function (domain) {
                    dns.lookup(domain, function (err, address, family) {
                        if (err != null)
                            return reject(err);
                        resolve(domain);
                    });
                });
            });
        });
    }
    static sendEmail(type, userid, to, subject, text, span) {
        return new Promise((resolve, reject) => {
            var transporter = null;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.smtp_url)) {
                transporter = nodemailer.createTransport(Config_1.Config.smtp_url);
            }
            else {
                transporter = nodemailer.createTransport({
                    service: Config_1.Config.smtp_service,
                    auth: {
                        user: Config_1.Config.smtp_user,
                        pass: Config_1.Config.smtp_pass
                    }
                });
            }
            let id = openflow_api_1.NoderedUtil.GetUniqueIdentifier();
            let imgurl = Config_1.Config.baseurl() + "read/" + id;
            text = text.split('\n').join('<br/>\n');
            let html = text + `<img src="${imgurl}" alt="isread" border="0" width="1" height="1">`;
            let from = Config_1.Config.smtp_from;
            if (Config_1.Config.NODE_ENV != "production") {
                Logger_1.Logger.instanse.warn("Skip sending email to " + to, span);
                Logger_1.Logger.instanse.info(text, span);
                resolve("email not sent");
            }
            else {
                transporter.sendMail({
                    from,
                    to,
                    subject,
                    html
                }, function (error, info) {
                    if (error) {
                        Logger_1.Logger.instanse.error(error, span);
                        reject(error);
                    }
                    else {
                        Logger_1.Logger.instanse.info("Email sent to " + to + " " + info.response, span);
                        var item = new openflow_api_1.Base();
                        item.readcount = 0;
                        item._type = type;
                        item.id = id;
                        item.from = from;
                        item.to = to;
                        item.text = text;
                        item.name = to + " " + subject;
                        item.userid = userid;
                        item.opened = [];
                        item.response = info.response;
                        item.read = false;
                        Config_1.Config.db.InsertOne(item, "mailhist", 1, true, Crypt_1.Crypt.rootToken(), span);
                        resolve(info.response);
                    }
                });
            }
        });
    }
    static async get_dashboardauth(req, res, next) {
        const span = (Config_1.Config.otel_trace_dashboardauth ? Logger_1.Logger.otel.startSpanExpress("LoginProvider.dashboardauth", req) : null);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            if (req.user) {
                Logger_1.Logger.instanse.verbose("User is signed in", span);
                const user = openflow_api_1.TokenUser.From(req.user);
                span === null || span === void 0 ? void 0 : span.setAttribute("username", user.username);
                if (user != null) {
                    const allowed = user.roles.filter(x => x.name == "dashboardusers" || x.name == "admins");
                    if (allowed.length > 0) {
                        Logger_1.Logger.instanse.verbose("Authorized " + user.username + " for " + req.url, span);
                        return res.send({
                            status: "success",
                            display_status: "Success",
                            message: "Connection OK"
                        });
                    }
                    else {
                        Logger_1.Logger.instanse.warn((user.username + " is not member of 'dashboardusers' for " + req.url), span);
                    }
                }
                else {
                    Logger_1.Logger.instanse.error("Failed casting user", span);
                }
            }
            const authorization = req.headers.authorization;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(authorization)) {
                res.statusCode = 401;
                res.setHeader('WWW-Authenticate', 'Basic realm="OpenFlow"');
                res.end('Unauthorized');
                return;
            }
            Logger_1.Logger.instanse.verbose("Lookup user by authentication header", span);
            var user = await Logger_1.Logger.DBHelper.FindByAuthorization(authorization, null, span);
            if (user != null) {
                const allowed = user.roles.filter(x => x.name == "dashboardusers" || x.name == "admins");
                if (allowed.length > 0) {
                    Logger_1.Logger.instanse.debug("User is authorized to see dashboard", span);
                    return res.send({
                        status: "success",
                        display_status: "Success",
                        message: "Connection OK"
                    });
                }
                else {
                    Logger_1.Logger.instanse.warn(user.username + " is not member of 'dashboardusers' for " + req.url, span);
                }
            }
            res.statusCode = 401;
            res.setHeader('WWW-Authenticate', 'Basic realm="OpenFlow"');
            res.end('Unauthorized');
            return;
        }
        catch (error) {
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static get_Signout(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.get_Signout", req);
        try {
            req.logout();
            const originalUrl = req.cookies.originalUrl;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl)) {
                Logger_1.Logger.instanse.debug("Redirect user to " + originalUrl, span);
                res.cookie("originalUrl", "", { expires: new Date(0) });
                LoginProvider.redirect(res, originalUrl);
            }
            else {
                Logger_1.Logger.instanse.debug("Redirect user to /", span);
                res.redirect("/");
            }
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static get_PassiveSignout(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.get_Signout", req);
        try {
            req.logout();
            const originalUrl = req.cookies.originalUrl;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl)) {
                Logger_1.Logger.instanse.debug("Redirect user to " + originalUrl, span);
                res.cookie("originalUrl", "", { expires: new Date(0) });
                LoginProvider.redirect(res, originalUrl);
            }
            else {
                Logger_1.Logger.instanse.debug("Redirect user to /", span);
                res.redirect("/Login");
            }
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static async get_user(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.user", req);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            res.setHeader("Content-Type", "application/json");
            if (req.user) {
                Logger_1.Logger.instanse.debug("return user " + req.user._id, span);
                await Logger_1.Logger.DBHelper.UserRoleUpdateId(req.user._id, false, span);
                const user = await Logger_1.Logger.DBHelper.FindById(req.user._id, span);
                user.validated = true;
                if (Config_1.Config.validate_user_form != "") {
                    if (!user.formvalidated)
                        user.validated = false;
                }
                if (Config_1.Config.validate_emails) {
                    if (!user.emailvalidated)
                        user.validated = false;
                }
                res.end(JSON.stringify(user));
            }
            else {
                Logger_1.Logger.instanse.debug("return nothing, not signed in", span);
                res.end(JSON.stringify({}));
            }
            res.end();
        }
        catch (error) {
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static get_jwt(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.jwt", req);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            res.setHeader("Content-Type", "application/json");
            if (req.user) {
                const user = openflow_api_1.TokenUser.From(req.user);
                span === null || span === void 0 ? void 0 : span.setAttribute("username", user.username);
                Logger_1.Logger.instanse.debug("return token for user " + req.user._id + " " + user.name, span);
                res.end(JSON.stringify({ jwt: Crypt_1.Crypt.createToken(user, Config_1.Config.shorttoken_expires_in), user: user }));
            }
            else {
                Logger_1.Logger.instanse.verbose("return nothing, not signed in", span);
                res.end(JSON.stringify({ jwt: "" }));
            }
            res.end();
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static get_jwtlong(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.jwtlong", req);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            res.setHeader("Content-Type", "application/json");
            if (req.user) {
                const user = openflow_api_1.TokenUser.From(req.user);
                span === null || span === void 0 ? void 0 : span.setAttribute("username", user.username);
                if (!(user.validated == true) && Config_1.Config.validate_user_form != "") {
                    Logger_1.Logger.instanse.error("return nothing, user is not validated yet", span);
                    res.end(JSON.stringify({ jwt: "" }));
                }
                else {
                    Logger_1.Logger.instanse.debug("return token for user " + req.user._id + " " + user.name, span);
                    res.end(JSON.stringify({ jwt: Crypt_1.Crypt.createToken(user, Config_1.Config.longtoken_expires_in), user: user }));
                }
            }
            else {
                Logger_1.Logger.instanse.error("return nothing, not signed in", span);
                res.end(JSON.stringify({ jwt: "" }));
            }
            res.end();
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static async post_jwt(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.jwt", req);
        // logger.debug("/jwt " + !(req.user == null));
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            const rawAssertion = req.body.token;
            const user = await LoginProvider.validateToken(rawAssertion, span);
            const tuser = openflow_api_1.TokenUser.From(user);
            span === null || span === void 0 ? void 0 : span.setAttribute("username", user.username);
            res.setHeader("Content-Type", "application/json");
            Logger_1.Logger.instanse.debug("Recreating jwt token", span);
            res.end(JSON.stringify({ jwt: Crypt_1.Crypt.createToken(tuser, Config_1.Config.shorttoken_expires_in) }));
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static async get_config(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.config", req);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            let _url = Config_1.Config.basewsurl();
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.api_ws_url))
                _url = Config_1.Config.api_ws_url;
            if (!_url.endsWith("/"))
                _url += "/";
            if (req.user) {
                const user = openflow_api_1.TokenUser.From(req.user);
                span === null || span === void 0 ? void 0 : span.setAttribute("username", user.username);
            }
            let nodered_domain_schema = Config_1.Config.nodered_domain_schema;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(nodered_domain_schema)) {
                nodered_domain_schema = "$nodered_id$." + Config_1.Config.domain;
            }
            let forceddomains = [];
            var providers = await Logger_1.Logger.DBHelper.GetProviders(null);
            for (let i = 0; i < providers.length; i++) {
                var provider = providers[i];
                if (provider.forceddomains && Array.isArray(provider.forceddomains)) {
                    forceddomains = forceddomains.concat(provider.forceddomains);
                }
            }
            const res2 = {
                wshost: _url,
                wsurl: _url,
                domain: Config_1.Config.domain,
                auto_create_users: Config_1.Config.auto_create_users,
                allow_personal_nodered: Config_1.Config.allow_personal_nodered,
                auto_create_personal_nodered_group: Config_1.Config.auto_create_personal_nodered_group,
                auto_create_personal_noderedapi_group: Config_1.Config.auto_create_personal_noderedapi_group,
                namespace: Config_1.Config.namespace,
                nodered_domain_schema: nodered_domain_schema,
                websocket_package_size: Config_1.Config.websocket_package_size,
                version: Config_1.Config.version,
                stripe_api_key: Config_1.Config.stripe_api_key,
                getting_started_url: Config_1.Config.getting_started_url,
                validate_user_form: Config_1.Config.validate_user_form,
                validate_emails: Config_1.Config.validate_emails,
                forgot_pass_emails: Config_1.Config.forgot_pass_emails,
                supports_watch: Config_1.Config.supports_watch,
                nodered_images: Config_1.Config.nodered_images,
                amqp_enabled_exchange: Config_1.Config.amqp_enabled_exchange,
                multi_tenant: Config_1.Config.multi_tenant,
                enable_entity_restriction: Config_1.Config.enable_entity_restriction,
                enable_web_tours: Config_1.Config.enable_web_tours,
                enable_nodered_tours: Config_1.Config.enable_nodered_tours,
                collections_with_text_index: DatabaseConnection_1.DatabaseConnection.collections_with_text_index,
                timeseries_collections: DatabaseConnection_1.DatabaseConnection.timeseries_collections,
                ping_clients_interval: Config_1.Config.ping_clients_interval,
                validlicense: Logger_1.Logger.License.validlicense,
                forceddomains: forceddomains
            };
            Logger_1.Logger.instanse.debug("Return configuration settings", span);
            res.end(JSON.stringify(res2));
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static async post_AddTokenRequest(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.login", req);
        try {
            const key = req.body.key;
            let exists = await Logger_1.Logger.DBHelper.FindRequestTokenID(key, span);
            if (!openflow_api_1.NoderedUtil.IsNullUndefinded(exists)) {
                Logger_1.Logger.instanse.error("Key has already been used! " + key, span);
                return res.status(500).send({ message: "Illegal key" });
            }
            await Logger_1.Logger.DBHelper.AdddRequestTokenID(key, {}, span);
            Logger_1.Logger.instanse.debug(key, span);
            res.status(200).send({ message: "ok" });
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static async get_GetTokenRequest(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.login", req);
        try {
            const key = req.query.key;
            let exists = null;
            exists = await Logger_1.Logger.DBHelper.FindRequestTokenID(key, span);
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(exists)) {
                Logger_1.Logger.instanse.error("Unknown key " + key, span);
                res.status(200).send({ message: "Illegal key" });
                return;
            }
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(exists.jwt)) {
                if (Config_1.Config.validate_user_form != "") {
                    try {
                        var tuser = await await Crypt_1.Crypt.verityToken(exists.jwt);
                        var user = await Logger_1.Logger.DBHelper.FindById(tuser._id, span);
                        if (user.validated == true) {
                            await Logger_1.Logger.DBHelper.RemoveRequestTokenID(key, span);
                            Logger_1.Logger.instanse.debug("return jwt for " + key, span);
                            res.status(200).send(Object.assign(exists, { message: "ok" }));
                        }
                        else {
                            Logger_1.Logger.instanse.debug("User not validated yet, for key " + key + " user " + user.name + " " + user._id, span);
                            res.status(200).send({ message: "ok" });
                        }
                    }
                    catch (error) {
                        Logger_1.Logger.instanse.error(error, span);
                    }
                }
                else {
                    Logger_1.Logger.instanse.debug("return jwt for " + key, span);
                    res.status(200).send(Object.assign(exists, { message: "ok" }));
                    await Logger_1.Logger.DBHelper.RemoveRequestTokenID(key, span);
                }
            }
            else {
                Logger_1.Logger.instanse.debug("No jwt for " + key, span);
                res.status(200).send(Object.assign(exists, { message: "ok" }));
            }
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            try {
                res.status(500).send({ message: error.message ? error.message : error });
            }
            catch (error) {
            }
        }
        finally {
            try {
                res.end();
            }
            catch (error) {
            }
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static async get_login(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.login", req);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            let key = req.query.key;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(key) && !openflow_api_1.NoderedUtil.IsNullEmpty(req.cookies.requesttoken))
                key = req.cookies.requesttoken;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(key)) {
                if (req.user) {
                    const user = await Logger_1.Logger.DBHelper.FindById(req.user._id, span);
                    var exists = await Logger_1.Logger.DBHelper.FindRequestTokenID(key, span);
                    if (!openflow_api_1.NoderedUtil.IsNullUndefinded(exists)) {
                        Logger_1.Logger.instanse.debug("adding jwt for request token " + key, span);
                        await Logger_1.Logger.DBHelper.AdddRequestTokenID(key, { jwt: Crypt_1.Crypt.createToken(user, Config_1.Config.longtoken_expires_in) }, span);
                        res.cookie("requesttoken", "", { expires: new Date(0) });
                    }
                }
                else {
                    res.cookie("requesttoken", key, { maxAge: 36000, httpOnly: true });
                }
            }
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(req.query.key)) {
                if (req.user) {
                    res.cookie("originalUrl", "", { expires: new Date(0) });
                    Logger_1.Logger.instanse.debug("User signed in, with key " + key, span);
                    this.redirect(res, "/");
                }
                else {
                    try {
                        res.cookie("originalUrl", req.originalUrl, { maxAge: 900000, httpOnly: true });
                    }
                    catch (error) {
                    }
                    Logger_1.Logger.instanse.debug("User not signed in, redirect to /login", span);
                    this.redirect(res, "/login");
                }
            }
            let user;
            let tuser;
            if (req.user) {
                await Logger_1.Logger.DBHelper.UserRoleUpdate(req.user, false, span);
                user = await Logger_1.Logger.DBHelper.FindById(req.user._id, span);
                user.validated = true;
                if (Config_1.Config.validate_user_form != "") {
                    if (!user.formvalidated)
                        user.validated = false;
                }
                if (Config_1.Config.validate_emails) {
                    if (!user.emailvalidated)
                        user.validated = false;
                }
                tuser = openflow_api_1.TokenUser.From(user);
            }
            const originalUrl = req.cookies.originalUrl;
            const validateurl = req.cookies.validateurl;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl) && !req.originalUrl.startsWith("/login")) {
                Logger_1.Logger.instanse.debug("Save originalUrl as " + originalUrl, span);
                res.cookie("originalUrl", req.originalUrl, { maxAge: 900000, httpOnly: true });
            }
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(validateurl)) {
                if (tuser != null) {
                    if (tuser.validated) {
                        Logger_1.Logger.DBHelper.UserRoleUpdate(tuser, false, span);
                    }
                    if (!(tuser.validated == true) && Config_1.Config.validate_user_form != "") {
                    }
                    else {
                        res.cookie("validateurl", "", { expires: new Date(0) });
                        res.cookie("originalUrl", "", { expires: new Date(0) });
                        Logger_1.Logger.instanse.debug("redirect to validateurl /#" + validateurl, span);
                        this.redirect(res, "/#" + validateurl);
                        return;
                    }
                }
            }
            if (req.user != null && !openflow_api_1.NoderedUtil.IsNullEmpty(originalUrl) && tuser.validated) {
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.validate_user_form) && req.user.validated == true) {
                    Logger_1.Logger.instanse.debug("user validated, redirect to " + originalUrl, span);
                    this.redirect(res, originalUrl);
                    return;
                }
                else if (openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.validate_user_form)) {
                    Logger_1.Logger.instanse.debug("user signed in, redirect to " + originalUrl, span);
                    this.redirect(res, originalUrl);
                    return;
                }
            }
            if (tuser != null && tuser.validated) {
                Logger_1.Logger.instanse.debug("redirect to /", span);
                this.redirect(res, "/");
            }
            else {
                Logger_1.Logger.instanse.debug("return PassiveLogin.html", span);
                const file = path.join(__dirname, 'public', 'PassiveLogin.html');
                res.sendFile(file);
            }
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            try {
                return res.status(500).send({ message: error.message ? error.message : error });
            }
            catch (error) {
            }
        }
        Logger_1.Logger.otel.endSpan(span);
    }
    static async get_validateuserform(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.validateuserform", req);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            res.setHeader("Content-Type", "application/json");
            if (openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.validate_user_form)) {
                Logger_1.Logger.instanse.debug("No validate user form set, return nothing", span);
                res.end(JSON.stringify({}));
                res.end();
                Logger_1.Logger.otel.endSpan(span);
                return;
            }
            var forms = await Config_1.Config.db.query({ query: { _id: Config_1.Config.validate_user_form, _type: "form" }, top: 1, collectionname: "forms", jwt: Crypt_1.Crypt.rootToken() }, span);
            if (forms.length == 1) {
                Logger_1.Logger.instanse.debug("Return form " + Config_1.Config.validate_user_form, span);
                res.end(JSON.stringify(forms[0]));
                res.end();
                Logger_1.Logger.otel.endSpan(span);
                return;
            }
            Logger_1.Logger.instanse.error("validate_user_form " + Config_1.Config.validate_user_form + " does not exists!", span);
            Config_1.Config.validate_user_form = "";
            res.end(JSON.stringify({}));
            res.end();
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
        return;
    }
    static async get_read(req, res) {
        if (openflow_api_1.NoderedUtil.IsNullEmpty(req.params.id))
            return res.end(JSON.stringify({ "message": "notok" }));
        const buffer = Buffer.alloc(43);
        buffer.write('R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=', 'base64');
        res.writeHead(200, { 'Content-Type': 'image/gif' });
        res.end(buffer, 'binary');
        try {
            const id = req.params.id;
            const dt = new Date(new Date().toISOString());
            const ip = LoginProvider.remoteip(req);
            let domain = "";
            try {
                domain = await LoginProvider.reverseLookup(ip);
            }
            catch (error) {
            }
            const agent = req.headers['user-agent'];
            const UpdateDoc = { "$set": { "_modified": dt, "read": true }, "$push": { "opened": { dt, ip, domain, agent } }, "$inc": { "readcount": 1 } };
            var res2 = await Config_1.Config.db._UpdateOne({ id }, UpdateDoc, "mailhist", 1, true, Crypt_1.Crypt.rootToken(), null);
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, null);
        }
    }
    static async post_validateuserform(req, res) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.postvalidateuserform", req);
        res.setHeader("Content-Type", "application/json");
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            if (req.user) {
                var u = req.user;
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(u._id))
                    u = await Logger_1.Logger.DBHelper.FindById(u._id, span);
                var tuser = openflow_api_1.TokenUser.From(u);
                if (req.body && req.body.data) {
                    if (!tuser.formvalidated || tuser.formvalidated) {
                        delete req.body.data._id;
                        delete req.body.data.username;
                        delete req.body.data.disabled;
                        delete req.body.data.type;
                        delete req.body.data.roles;
                        delete req.body.data.submit;
                        delete req.body.data.federationids;
                        delete req.body.data.nodered;
                        delete req.body.data.billing;
                        delete req.body.data.clientagent;
                        delete req.body.data.clientversion;
                        const UpdateDoc = { "$set": {} };
                        const keys = Object.keys(req.body.data);
                        keys.forEach(key => {
                            if (key.startsWith("_")) {
                            }
                            else if (key.indexOf("$") > -1) {
                            }
                            else {
                                UpdateDoc.$set[key] = req.body.data[key];
                            }
                        });
                        UpdateDoc.$set["formvalidated"] = true;
                        if (Config_1.Config.validate_emails) {
                            if (Config_1.Config.smtp_service == "gmail") {
                                if (openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.smtp_user) || openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.smtp_pass)) {
                                    Logger_1.Logger.instanse.error("Disabling email validation, missing login information fot gmail", span);
                                    Config_1.Config.validate_emails = false;
                                }
                            }
                            else if (openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.smtp_url)) {
                                Logger_1.Logger.instanse.error("Disabling email validation, missing smtp_url", span);
                                Config_1.Config.validate_emails = false;
                            }
                            else if (openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.smtp_from)) {
                                Logger_1.Logger.instanse.error("Disabling email validation, missing smtp_from", span);
                                Config_1.Config.validate_emails = false;
                            }
                        }
                        Config_1.Config.smtp_service = Config_1.Config.getEnv("smtp_service", "");
                        Config_1.Config.smtp_from = Config_1.Config.getEnv("smtp_from", "");
                        Config_1.Config.smtp_user = Config_1.Config.getEnv("smtp_user", "");
                        Config_1.Config.smtp_pass = Config_1.Config.getEnv("smtp_service", "");
                        if (Config_1.Config.validate_emails) {
                            let email = tuser.username;
                            if (tuser.email && tuser.email.indexOf("@") > -1)
                                email = tuser.email;
                            if (req.body.data.email)
                                email = req.body.data.email;
                            if (email.indexOf("@") > -1) {
                                if (Config_1.Config.debounce_lookup) {
                                    const response = await got.get("https://disposable.debounce.io/?email=" + email);
                                    const body = JSON.parse(response.body);
                                    if (body.disposable == true) {
                                        throw new Error("Please use a valid and non temporary email address");
                                    }
                                }
                                if (Config_1.Config.validate_emails_disposable) {
                                    var domain = await Logger_1.Logger.DBHelper.GetDisposableDomain(email, span);
                                    if (domain != null) {
                                        throw new Error("Please use a valid and non temporary email address");
                                    }
                                }
                            }
                            if (email.indexOf("@") > -1) {
                                // https://disposable.debounce.io/?email=info@example.com
                                email = email.toLowerCase();
                                var exists = await Config_1.Config.db.query({ query: { "_id": { "$ne": tuser._id }, "$or": [{ "username": email }, { "email": email }], "_type": "user" }, collectionname: "users", jwt: Crypt_1.Crypt.rootToken() }, span);
                                if (exists.length > 0) {
                                    Logger_1.Logger.instanse.error(tuser.name + " trying to register email " + email + " already used by " + exists[0].name + " (" + exists[0]._id + ")", span);
                                    email = "";
                                    delete UpdateDoc.$set["email"];
                                    UpdateDoc.$set["formvalidated"] = false;
                                    throw new Error("email already in use by another user");
                                }
                            }
                            if (email.indexOf("@") > -1) {
                                if (tuser.emailvalidated == true) {
                                    UpdateDoc.$set["validated"] = true;
                                    tuser.validated = true;
                                }
                                else {
                                    const code = openflow_api_1.NoderedUtil.GetUniqueIdentifier();
                                    UpdateDoc.$set["_mailcode"] = code;
                                    this.sendEmail("validate", tuser._id, email, 'Validate email in OpenIAP flow', `Hi ${tuser.name}\nPlease use the below code to validate your email\n${code}`, span);
                                }
                            }
                            else {
                                Logger_1.Logger.instanse.error(tuser.name + " email is mandatory)", span);
                                throw new Error("email is mandatory.");
                            }
                        }
                        else {
                            UpdateDoc.$set["validated"] = true;
                            tuser.validated = true;
                        }
                        Logger_1.Logger.instanse.debug("Update user " + tuser.name + " information", span);
                        var res2 = await Config_1.Config.db._UpdateOne({ "_id": tuser._id }, UpdateDoc, "users", 1, true, Crypt_1.Crypt.rootToken(), span);
                        await Logger_1.Logger.DBHelper.UserRoleUpdate(tuser, false, span);
                    }
                    if (!(tuser.validated == true) && Config_1.Config.validate_user_form != "") {
                        Logger_1.Logger.instanse.debug("User not validated, return no token for user " + tuser.name, span);
                        res.end(JSON.stringify({ jwt: "" }));
                    }
                    else {
                        Logger_1.Logger.instanse.debug("Return new jwt for user " + tuser.name, span);
                        res.end(JSON.stringify({ jwt: Crypt_1.Crypt.createToken(tuser, Config_1.Config.longtoken_expires_in), user: tuser }));
                    }
                }
                else if (req.body) {
                    if (req.body.resend) {
                        var exists = await Config_1.Config.db.query({ query: { "_id": tuser._id, "_type": "user" }, collectionname: "users", jwt: Crypt_1.Crypt.rootToken() }, span);
                        if (exists.length > 0) {
                            var u = exists[0];
                            let email = u.username;
                            if (u.email.indexOf("@") > -1)
                                email = u.email;
                            u._mailcode = openflow_api_1.NoderedUtil.GetUniqueIdentifier();
                            this.sendEmail("validate", u._id, email, 'Validate email in OpenIAP flow', `Hi ${u.name}\nPlease use the below code to validate your email\n${u._mailcode}`, span);
                            const UpdateDoc = { "$set": {} };
                            UpdateDoc.$set["_mailcode"] = u._mailcode;
                            var res2 = await Config_1.Config.db._UpdateOne({ "_id": tuser._id }, UpdateDoc, "users", 1, true, Crypt_1.Crypt.rootToken(), span);
                            await Logger_1.Logger.DBHelper.UserRoleUpdate(tuser, false, span);
                            res.end(JSON.stringify({ jwt: "" }));
                        }
                        else {
                            res.end(JSON.stringify({ jwt: "" }));
                        }
                    }
                    else if (req.body.code) {
                        var exists = await Config_1.Config.db.query({ query: { "_id": tuser._id, "_type": "user" }, collectionname: "users", jwt: Crypt_1.Crypt.rootToken() }, span);
                        if (exists.length > 0) {
                            var u = exists[0];
                            if (u._mailcode == req.body.code) {
                                // @ts-ignore
                                delete u._mailcode;
                                u.validated = true;
                                u.emailvalidated = true;
                                await Logger_1.Logger.DBHelper.Save(u, Crypt_1.Crypt.rootToken(), span);
                                // const UpdateDoc: any = { "$set": {}, "$unset": {} };
                                // UpdateDoc.$unset["_mailcode"] = "";
                                // UpdateDoc.$set["validated"] = true;
                                // UpdateDoc.$set["emailvalidated"] = true;
                                // var res2 = await Config.db._UpdateOne({ "_id": tuser._id }, UpdateDoc, "users", 1, true, Crypt.rootToken(), span);
                                await Logger_1.Logger.DBHelper.UserRoleUpdate(tuser, false, span);
                                res.end(JSON.stringify({ jwt: Crypt_1.Crypt.createToken(tuser, Config_1.Config.longtoken_expires_in), user: tuser }));
                                return;
                            }
                            else {
                                throw new Error("Wrong validation code for " + tuser.name);
                            }
                        }
                        res.end(JSON.stringify({ jwt: "" }));
                    }
                    else {
                        res.end(JSON.stringify({ jwt: "" }));
                    }
                }
            }
            else {
                Logger_1.Logger.instanse.error("User no longer signed in", span);
                res.end(JSON.stringify({ jwt: "" }));
            }
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        Logger_1.Logger.otel.endSpan(span);
        res.end();
    }
    static async post_forgotpassword(req, res) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.postvalidateuserform", req);
        res.setHeader("Content-Type", "application/json");
        try {
            if (req.body && req.body.email) {
                const id = openflow_api_1.NoderedUtil.GetUniqueIdentifier();
                const email = req.body.email;
                let user = await Config_1.Config.db.getbyusername(req.body.email, null, Crypt_1.Crypt.rootToken(), true, span);
                if (user == null) {
                    Logger_1.Logger.instanse.error("Received unknown email " + email, span);
                    return res.end(JSON.stringify({ id }));
                }
                const code = openflow_api_1.NoderedUtil.GetUniqueIdentifier();
                var key = ("forgotpass_" + id).toString();
                let item = await Logger_1.Logger.DBHelper.memoryCache.wrap(key, () => {
                    Logger_1.Logger.instanse.info(`Add forgotpass if ${id} with code ${code} for ${email}`, span);
                    return { id, email, code };
                });
                if (item.id != id || item.email != email || item.code != code) {
                    Logger_1.Logger.instanse.error("Recevied wrong mail for id " + id, span);
                    return res.end(JSON.stringify({ id }));
                }
                this.sendEmail("pwreset", user._id, email, 'Reset password request', `Hi ${user.name}\nYour password for ${Config_1.Config.domain} can be reset by using the below validation code\n\n${code}\n\nIf you did not request a new password, please ignore this email.`, span);
                await Logger_1.Logger.DBHelper.UserRoleUpdate(user, false, span);
                return res.end(JSON.stringify({ id }));
            }
            else if (req.body && req.body.code && req.body.id && !req.body.password) {
                const code = req.body.code.trim();
                const id = req.body.id;
                var key = ("forgotpass_" + id).toString();
                let item = await Logger_1.Logger.DBHelper.memoryCache.wrap(key, () => {
                    return null;
                });
                if (item == null || item.id != id || item.code != code) {
                    if (item == null) {
                        Logger_1.Logger.instanse.error("Recevied unknown id " + id, span);
                    }
                    else {
                        Logger_1.Logger.instanse.error("Recevied wrong code for id " + id, span);
                    }
                    throw new Error("Recevied wrong code for id " + id);
                }
                return res.end(JSON.stringify({ id }));
            }
            else if (req.body && req.body.code && req.body.id && req.body.password) {
                const code = req.body.code.trim();
                const id = req.body.id;
                const password = req.body.password;
                var key = ("forgotpass_" + id).toString();
                let item = await Logger_1.Logger.DBHelper.memoryCache.wrap(key, () => {
                    Logger_1.Logger.instanse.debug("Add forgotpass : " + id, span);
                    return null;
                });
                if (item == null || item.id != id || item.code != code) {
                    Logger_1.Logger.instanse.error("Recevied wrong code for id " + id, span);
                    throw new Error("Recevied wrong code for id " + id);
                }
                let user = await Config_1.Config.db.getbyusername(item.email, null, Crypt_1.Crypt.rootToken(), true, span);
                user.newpassword = password;
                user.emailvalidated = true;
                user.validated = true;
                if (Config_1.Config.validate_user_form != "") {
                    if (!user.formvalidated)
                        user.validated = false;
                }
                if (Config_1.Config.validate_emails) {
                    if (!user.emailvalidated)
                        user.validated = false;
                }
                await Logger_1.Logger.DBHelper.Save(user, Crypt_1.Crypt.rootToken(), span);
                await Logger_1.Logger.DBHelper.UserRoleUpdate(user, false, span);
                return res.end(JSON.stringify({ id }));
            }
            res.end(JSON.stringify({}));
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        Logger_1.Logger.otel.endSpan(span);
        res.end();
    }
    static async get_loginproviders(req, res, next) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.loginproviders", req);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            const result = await Logger_1.Logger.DBHelper.GetProviders(span);
            res.setHeader("Content-Type", "application/json");
            res.end(JSON.stringify(result));
            res.end();
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            Logger_1.Logger.otel.endSpan(span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    static async get_download(req, res) {
        const span = Logger_1.Logger.otel.startSpanExpress("LoginProvider.download", req);
        try {
            span === null || span === void 0 ? void 0 : span.setAttribute("remoteip", LoginProvider.remoteip(req));
            let user = null;
            let jwt = null;
            const authHeader = req.headers.authorization;
            if (authHeader) {
                user = await Crypt_1.Crypt.verityToken(authHeader);
                jwt = Crypt_1.Crypt.createToken(user, Config_1.Config.downloadtoken_expires_in);
            }
            else if (req.user) {
                user = openflow_api_1.TokenUser.From(req.user);
                jwt = Crypt_1.Crypt.createToken(user, Config_1.Config.downloadtoken_expires_in);
            }
            if (user == null) {
                return res.status(404).send({ message: 'Route ' + req.url + ' Not found.' });
            }
            const id = req.params.id;
            const rows = await Config_1.Config.db.query({ query: { _id: safeObjectID(id) }, top: 1, collectionname: "files", jwt }, span);
            if (rows == null || rows.length != 1) {
                return res.status(404).send({ message: 'id ' + id + ' Not found.' });
            }
            const file = rows[0];
            const bucket = new mongodb_1.GridFSBucket(Config_1.Config.db.db);
            let downloadStream = bucket.openDownloadStream(safeObjectID(id));
            res.set('Content-Type', file.contentType);
            res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
            res.set('Content-Length', file.length);
            downloadStream.on("error", function (err) {
                res.end();
            });
            downloadStream.pipe(res);
        }
        catch (error) {
            Logger_1.Logger.instanse.error(error, span);
            return res.status(500).send({ message: error.message ? error.message : error });
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
}
exports.LoginProvider = LoginProvider;
LoginProvider._providers = {};
//# sourceMappingURL=LoginProvider.js.map