"use strict";
/*
 *  This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
 *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
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
*/
var misc_1 = require("@cocalc/util/misc");
var uuid_1 = require("uuid");
var is_account_available_1 = __importDefault(require("@cocalc/server/auth/is-account-available"));
var is_domain_exclusive_sso_1 = __importDefault(require("@cocalc/server/auth/is-domain-exclusive-sso"));
var create_account_1 = __importDefault(require("@cocalc/server/accounts/create-account"));
var sign_in_1 = require("./sign-in");
var welcome_email_1 = __importDefault(require("@cocalc/server/email/welcome-email"));
var redeem_1 = __importDefault(require("@cocalc/server/auth/tokens/redeem"));
var server_settings_1 = require("@cocalc/server/settings/server-settings");
var get_params_1 = __importDefault(require("lib/api/get-params"));
var recaptcha_1 = __importDefault(require("@cocalc/server/auth/recaptcha"));
function signUp(req, res) {
    return __awaiter(this, void 0, void 0, function () {
        var _a, terms, email, password, firstName, lastName, registrationToken, isAnonymous, account_id, _err_1, issues, _b, email_signup, anonymous_signup, err_1, exclusive, err_2, account_id, err_3, err_4;
        return __generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    _a = (0, get_params_1.default)(req), terms = _a.terms, email = _a.email, password = _a.password, firstName = _a.firstName, lastName = _a.lastName, registrationToken = _a.registrationToken;
                    password = (password !== null && password !== void 0 ? password : "").trim();
                    email = (email !== null && email !== void 0 ? email : "").toLowerCase().trim();
                    firstName = (firstName ? firstName : "Anonymous").trim();
                    lastName = (lastName ? lastName : "User-".concat(Math.round(new Date().valueOf() / 1000))).trim();
                    registrationToken = (registrationToken !== null && registrationToken !== void 0 ? registrationToken : "").trim();
                    isAnonymous = !email;
                    if (!(!isAnonymous && email && password)) return [3 /*break*/, 5];
                    _c.label = 1;
                case 1:
                    _c.trys.push([1, 4, , 5]);
                    return [4 /*yield*/, (0, sign_in_1.getAccount)(email, password)];
                case 2:
                    account_id = _c.sent();
                    return [4 /*yield*/, (0, sign_in_1.signUserIn)(req, res, account_id)];
                case 3:
                    _c.sent();
                    return [2 /*return*/];
                case 4:
                    _err_1 = _c.sent();
                    return [3 /*break*/, 5];
                case 5:
                    if (!isAnonymous) {
                        issues = checkObviousConditions({ terms: terms, email: email, password: password });
                        if ((0, misc_1.len)(issues) > 0) {
                            res.json({ issues: issues });
                            return [2 /*return*/];
                        }
                    }
                    return [4 /*yield*/, (0, server_settings_1.getServerSettings)()];
                case 6:
                    _b = _c.sent(), email_signup = _b.email_signup, anonymous_signup = _b.anonymous_signup;
                    _c.label = 7;
                case 7:
                    _c.trys.push([7, 9, , 10]);
                    return [4 /*yield*/, (0, recaptcha_1.default)(req)];
                case 8:
                    _c.sent();
                    return [3 /*break*/, 10];
                case 9:
                    err_1 = _c.sent();
                    res.json({
                        issues: {
                            reCaptcha: err_1.message,
                        },
                    });
                    return [2 /*return*/];
                case 10:
                    if (!isAnonymous) return [3 /*break*/, 11];
                    // Check anonymous sign up conditions.
                    if (!anonymous_signup) {
                        res.json({
                            issues: {
                                email: "Anonymous account creation is disabled.",
                            },
                        });
                        return [2 /*return*/];
                    }
                    return [3 /*break*/, 14];
                case 11:
                    // Check the email sign up conditions.
                    if (!email_signup) {
                        res.json({
                            issues: {
                                email: "Email account creation is disabled.",
                            },
                        });
                        return [2 /*return*/];
                    }
                    return [4 /*yield*/, (0, is_domain_exclusive_sso_1.default)(email)];
                case 12:
                    exclusive = _c.sent();
                    if (exclusive) {
                        res.json({
                            issues: {
                                email: "To sign up with \"@".concat(exclusive, "\", you have to use the corresponding single sign on mechanism.  Delete your email address above, then click the SSO icon."),
                            },
                        });
                        return [2 /*return*/];
                    }
                    return [4 /*yield*/, (0, is_account_available_1.default)(email)];
                case 13:
                    if (!(_c.sent())) {
                        res.json({
                            issues: { email: "Email address \"".concat(email, "\" already in use.") },
                        });
                        return [2 /*return*/];
                    }
                    _c.label = 14;
                case 14:
                    _c.trys.push([14, 16, , 17]);
                    return [4 /*yield*/, (0, redeem_1.default)(registrationToken)];
                case 15:
                    _c.sent();
                    return [3 /*break*/, 17];
                case 16:
                    err_2 = _c.sent();
                    res.json({
                        issues: {
                            registrationToken: "Issue with registration token -- ".concat(err_2.message),
                        },
                    });
                    return [2 /*return*/];
                case 17:
                    _c.trys.push([17, 24, , 25]);
                    account_id = (0, uuid_1.v4)();
                    return [4 /*yield*/, (0, create_account_1.default)({
                            email: email,
                            password: password,
                            firstName: firstName,
                            lastName: lastName,
                            account_id: account_id,
                        })];
                case 18:
                    _c.sent();
                    if (!email) return [3 /*break*/, 22];
                    _c.label = 19;
                case 19:
                    _c.trys.push([19, 21, , 22]);
                    return [4 /*yield*/, (0, welcome_email_1.default)(email, account_id)];
                case 20:
                    _c.sent();
                    return [3 /*break*/, 22];
                case 21:
                    err_3 = _c.sent();
                    // 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 ".concat(email), err_3);
                    return [3 /*break*/, 22];
                case 22: return [4 /*yield*/, (0, sign_in_1.signUserIn)(req, res, account_id)];
                case 23:
                    _c.sent(); // sets a cookie
                    res.json({ account_id: account_id });
                    return [3 /*break*/, 25];
                case 24:
                    err_4 = _c.sent();
                    res.json({ error: err_4.message });
                    return [3 /*break*/, 25];
                case 25: return [2 /*return*/];
            }
        });
    });
}
exports.default = signUp;
function checkObviousConditions(_a) {
    var terms = _a.terms, email = _a.email, password = _a.password;
    var 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