"use strict";
/*
 *  This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
 *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/*
Sign up for a new account:

0. If email/password matches an existing account, just sign them in.  Reduces confusion.
1. Reject if password is absurdly weak.
2. Query the database to make sure the email address is not already taken.
3. Generate a random account_id. Do not check it is not already taken, since that's
   highly unlikely, and the insert in 4 would fail anyways.
4. Write account to the database.
5. Sign user in
*/
const misc_1 = require("@cocalc/util/misc");
const uuid_1 = require("uuid");
const is_account_available_1 = __importDefault(require("@cocalc/server/auth/is-account-available"));
const is_domain_exclusive_sso_1 = __importDefault(require("@cocalc/server/auth/is-domain-exclusive-sso"));
const create_account_1 = __importDefault(require("@cocalc/server/accounts/create-account"));
const sign_in_1 = require("./sign-in");
const welcome_email_1 = __importDefault(require("@cocalc/server/email/welcome-email"));
const redeem_1 = __importDefault(require("@cocalc/server/auth/tokens/redeem"));
const server_settings_1 = require("@cocalc/server/settings/server-settings");
const get_params_1 = __importDefault(require("lib/api/get-params"));
const recaptcha_1 = __importDefault(require("@cocalc/server/auth/recaptcha"));
async function signUp(req, res) {
    let { terms, email, password, firstName, lastName, registrationToken } = (0, get_params_1.default)(req);
    password = (password ?? "").trim();
    email = (email ?? "").toLowerCase().trim();
    firstName = (firstName ? firstName : "Anonymous").trim();
    lastName = (lastName ? lastName : `User-${Math.round(new Date().valueOf() / 1000)}`).trim();
    registrationToken = (registrationToken ?? "").trim();
    // if email is empty, then trying to create an anonymous account,
    // which may be allowed, depending on server settings.
    const isAnonymous = !email;
    if (!isAnonymous && email && password) {
        // Maybe there is already an account with this email and password?
        try {
            const account_id = await (0, sign_in_1.getAccount)(email, password);
            await (0, sign_in_1.signUserIn)(req, res, account_id);
            return;
        }
        catch (_err) {
            // fine -- just means they don't already have an account.
        }
    }
    if (!isAnonymous) {
        const issues = checkObviousConditions({ terms, email, password });
        if ((0, misc_1.len)(issues) > 0) {
            res.json({ issues });
            return;
        }
    }
    // The UI doesn't let users try to make an account via signUp if
    // email isn't enabled.  However, they might try to directly POST
    // to the API, so we check here as well.
    const { email_signup, anonymous_signup } = await (0, server_settings_1.getServerSettings)();
    try {
        await (0, recaptcha_1.default)(req);
    }
    catch (err) {
        res.json({
            issues: {
                reCaptcha: err.message,
            },
        });
        return;
    }
    if (isAnonymous) {
        // Check anonymous sign up conditions.
        if (!anonymous_signup) {
            res.json({
                issues: {
                    email: "Anonymous account creation is disabled.",
                },
            });
            return;
        }
    }
    else {
        // Check the email sign up conditions.
        if (!email_signup) {
            res.json({
                issues: {
                    email: "Email account creation is disabled.",
                },
            });
            return;
        }
        const exclusive = await (0, is_domain_exclusive_sso_1.default)(email);
        if (exclusive) {
            res.json({
                issues: {
                    email: `To sign up with "@${exclusive}", you have to use the corresponding single sign on mechanism.  Delete your email address above, then click the SSO icon.`,
                },
            });
            return;
        }
        if (!(await (0, is_account_available_1.default)(email))) {
            res.json({
                issues: { email: `Email address "${email}" already in use.` },
            });
            return;
        }
    }
    try {
        await (0, redeem_1.default)(registrationToken);
    }
    catch (err) {
        res.json({
            issues: {
                registrationToken: `Issue with registration token -- ${err.message}`,
            },
        });
        return;
    }
    try {
        const account_id = (0, uuid_1.v4)();
        await (0, create_account_1.default)({
            email,
            password,
            firstName,
            lastName,
            account_id,
        });
        if (email) {
            try {
                await (0, welcome_email_1.default)(email, account_id);
            }
            catch (err) {
                // Expected to fail, e.g., when sendgrid or smtp not configured yet.
                // TODO: should log using debug instead of console?
                console.log(`WARNING: failed to send welcome email to ${email}`, err);
            }
        }
        await (0, sign_in_1.signUserIn)(req, res, account_id); // sets a cookie
        res.json({ account_id });
    }
    catch (err) {
        res.json({ error: err.message });
    }
}
exports.default = signUp;
function checkObviousConditions({ terms, email, password }) {
    const issues = {};
    if (!terms) {
        issues.terms = "You must agree to the terms of usage.";
    }
    if (!email || !(0, misc_1.is_valid_email_address)(email)) {
        issues.email = "You must provide a valid email address.";
    }
    if (!password || password.length < 6) {
        issues.password = "Your password must not be trivial to guess.";
    }
    return issues;
}
//# sourceMappingURL=sign-up.js.map