"use strict";
(() => {
var exports = {};
exports.id = 1764;
exports.ids = [1764,1992];
exports.modules = {

/***/ 770640:
/***/ ((module) => {

module.exports = require("cookies");

/***/ }),

/***/ 922687:
/***/ ((module) => {

module.exports = require("password-hash");

/***/ }),

/***/ 446555:
/***/ ((module) => {

module.exports = import("uuid");;

/***/ }),

/***/ 439491:
/***/ ((module) => {

module.exports = require("assert");

/***/ }),

/***/ 714300:
/***/ ((module) => {

module.exports = require("buffer");

/***/ }),

/***/ 532081:
/***/ ((module) => {

module.exports = require("child_process");

/***/ }),

/***/ 706113:
/***/ ((module) => {

module.exports = require("crypto");

/***/ }),

/***/ 809523:
/***/ ((module) => {

module.exports = require("dns");

/***/ }),

/***/ 582361:
/***/ ((module) => {

module.exports = require("events");

/***/ }),

/***/ 657147:
/***/ ((module) => {

module.exports = require("fs");

/***/ }),

/***/ 113685:
/***/ ((module) => {

module.exports = require("http");

/***/ }),

/***/ 795687:
/***/ ((module) => {

module.exports = require("https");

/***/ }),

/***/ 241808:
/***/ ((module) => {

module.exports = require("net");

/***/ }),

/***/ 272254:
/***/ ((module) => {

module.exports = require("node:buffer");

/***/ }),

/***/ 487561:
/***/ ((module) => {

module.exports = require("node:fs");

/***/ }),

/***/ 788849:
/***/ ((module) => {

module.exports = require("node:http");

/***/ }),

/***/ 22286:
/***/ ((module) => {

module.exports = require("node:https");

/***/ }),

/***/ 487503:
/***/ ((module) => {

module.exports = require("node:net");

/***/ }),

/***/ 149411:
/***/ ((module) => {

module.exports = require("node:path");

/***/ }),

/***/ 497742:
/***/ ((module) => {

module.exports = require("node:process");

/***/ }),

/***/ 484492:
/***/ ((module) => {

module.exports = require("node:stream");

/***/ }),

/***/ 572477:
/***/ ((module) => {

module.exports = require("node:stream/web");

/***/ }),

/***/ 941041:
/***/ ((module) => {

module.exports = require("node:url");

/***/ }),

/***/ 447261:
/***/ ((module) => {

module.exports = require("node:util");

/***/ }),

/***/ 165628:
/***/ ((module) => {

module.exports = require("node:zlib");

/***/ }),

/***/ 822037:
/***/ ((module) => {

module.exports = require("os");

/***/ }),

/***/ 371017:
/***/ ((module) => {

module.exports = require("path");

/***/ }),

/***/ 677282:
/***/ ((module) => {

module.exports = require("process");

/***/ }),

/***/ 285477:
/***/ ((module) => {

module.exports = require("punycode");

/***/ }),

/***/ 12781:
/***/ ((module) => {

module.exports = require("stream");

/***/ }),

/***/ 371576:
/***/ ((module) => {

module.exports = require("string_decoder");

/***/ }),

/***/ 924404:
/***/ ((module) => {

module.exports = require("tls");

/***/ }),

/***/ 76224:
/***/ ((module) => {

module.exports = require("tty");

/***/ }),

/***/ 257310:
/***/ ((module) => {

module.exports = require("url");

/***/ }),

/***/ 473837:
/***/ ((module) => {

module.exports = require("util");

/***/ }),

/***/ 271267:
/***/ ((module) => {

module.exports = require("worker_threads");

/***/ }),

/***/ 959796:
/***/ ((module) => {

module.exports = require("zlib");

/***/ }),

/***/ 449376:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {


/*
 *  This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
 *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
 */
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.pii_expire = exports.pii_retention_to_future = void 0;
const misc_1 = __webpack_require__(854006);
const server_settings_1 = __webpack_require__(558305);
// this converts what's in the pii_expired setting to a new Date in the future
function pii_retention_to_future(pii_retention, data) {
    if (!pii_retention)
        return;
    const future = (0, misc_1.expire_time)(pii_retention);
    if (data != null) {
        data.expire = future;
    }
    return future;
}
exports.pii_retention_to_future = pii_retention_to_future;
// use this to get the "expire" value for storing certain entries in the DB,
// which contain personally identifiable information.
// if data is set, it's expire field will be set. in any case, it returns the "Date"
// in the future.
async function pii_expire(db, data) {
    const settings = await (0, server_settings_1.get_server_settings)(db);
    return pii_retention_to_future(settings.pii_retention, data);
}
exports.pii_expire = pii_expire;
//# sourceMappingURL=pii.js.map

/***/ }),

/***/ 558305:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {


Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.get_server_settings = void 0;
const async_utils_1 = __webpack_require__(644181);
// just to make this async friendly, that's all
async function get_server_settings(db) {
    return await (0, async_utils_1.callback2)(db.get_server_settings_cached);
}
exports.get_server_settings = get_server_settings;
//# sourceMappingURL=server-settings.js.map

/***/ }),

/***/ 482260:
/***/ ((module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ signUp)
/* harmony export */ });
/* harmony import */ var _cocalc_util_misc__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(854006);
/* harmony import */ var _cocalc_util_misc__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_cocalc_util_misc__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(446555);
/* harmony import */ var _cocalc_server_auth_is_account_available__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(29459);
/* harmony import */ var _cocalc_server_auth_is_account_available__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_auth_is_account_available__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _cocalc_server_auth_is_domain_exclusive_sso__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(497364);
/* harmony import */ var _cocalc_server_auth_is_domain_exclusive_sso__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_auth_is_domain_exclusive_sso__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _cocalc_server_accounts_create_account__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(2113);
/* harmony import */ var _cocalc_server_accounts_create_account__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_accounts_create_account__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _sign_in__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(403408);
/* harmony import */ var _cocalc_server_email_welcome_email__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(508905);
/* harmony import */ var _cocalc_server_email_welcome_email__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_email_welcome_email__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var _cocalc_server_auth_tokens_redeem__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(14790);
/* harmony import */ var _cocalc_server_auth_tokens_redeem__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_auth_tokens_redeem__WEBPACK_IMPORTED_MODULE_7__);
/* harmony import */ var _cocalc_server_settings_server_settings__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(526177);
/* harmony import */ var _cocalc_server_settings_server_settings__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_settings_server_settings__WEBPACK_IMPORTED_MODULE_8__);
/* harmony import */ var lib_api_get_params__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(26438);
/* harmony import */ var _cocalc_server_auth_recaptcha__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(437415);
/* harmony import */ var _cocalc_server_auth_recaptcha__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_auth_recaptcha__WEBPACK_IMPORTED_MODULE_9__);
var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([uuid__WEBPACK_IMPORTED_MODULE_1__]);
uuid__WEBPACK_IMPORTED_MODULE_1__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0];
/*
 *  This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
 *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
 */ /*
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
*/ 










async function signUp(req, res) {
    let { terms , email , password , firstName , lastName , registrationToken  } = (0,lib_api_get_params__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .Z)(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__WEBPACK_IMPORTED_MODULE_5__.getAccount)(email, password);
            await (0,_sign_in__WEBPACK_IMPORTED_MODULE_5__.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,_cocalc_util_misc__WEBPACK_IMPORTED_MODULE_0__.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,_cocalc_server_settings_server_settings__WEBPACK_IMPORTED_MODULE_8__.getServerSettings)();
    try {
        await _cocalc_server_auth_recaptcha__WEBPACK_IMPORTED_MODULE_9___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 _cocalc_server_auth_is_domain_exclusive_sso__WEBPACK_IMPORTED_MODULE_3___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 _cocalc_server_auth_is_account_available__WEBPACK_IMPORTED_MODULE_2___default()(email)) {
            res.json({
                issues: {
                    email: `Email address "${email}" already in use.`
                }
            });
            return;
        }
    }
    try {
        await _cocalc_server_auth_tokens_redeem__WEBPACK_IMPORTED_MODULE_7___default()(registrationToken);
    } catch (err1) {
        res.json({
            issues: {
                registrationToken: `Issue with registration token -- ${err1.message}`
            }
        });
        return;
    }
    try {
        const account_id1 = (0,uuid__WEBPACK_IMPORTED_MODULE_1__.v4)();
        await _cocalc_server_accounts_create_account__WEBPACK_IMPORTED_MODULE_4___default()({
            email,
            password,
            firstName,
            lastName,
            account_id: account_id1
        });
        if (email) {
            try {
                await _cocalc_server_email_welcome_email__WEBPACK_IMPORTED_MODULE_6___default()(email, account_id1);
            } catch (err2) {
                // 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}`, err2);
            }
        }
        await (0,_sign_in__WEBPACK_IMPORTED_MODULE_5__.signUserIn)(req, res, account_id1); // sets a cookie
        res.json({
            account_id: account_id1
        });
    } catch (err3) {
        res.json({
            error: err3.message
        });
    }
}
function checkObviousConditions({ terms , email , password  }) {
    const issues = {};
    if (!terms) {
        issues.terms = "You must agree to the terms of usage.";
    }
    if (!email || !(0,_cocalc_util_misc__WEBPACK_IMPORTED_MODULE_0__.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;
}

__webpack_async_result__();
} catch(e) { __webpack_async_result__(e); } });

/***/ }),

/***/ 2113:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


/*
Create account.  Doesn't do any checking that server allows
for this type of account, etc. -- that is assumed to have been
done before calling this.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const pool_1 = __importDefault(__webpack_require__(541808));
const password_hash_1 = __importDefault(__webpack_require__(987909));
const account_creation_actions_1 = __importStar(__webpack_require__(786791));
async function createAccount({ email, password, firstName, lastName, account_id, }) {
    const pool = (0, pool_1.default)();
    await pool.query("INSERT INTO accounts (email_address, password_hash, first_name, last_name, account_id, created) VALUES($1::TEXT, $2::TEXT, $3::TEXT, $4::TEXT, $5::UUID, NOW())", [
        email ? email : undefined,
        password ? (0, password_hash_1.default)(password) : undefined,
        firstName,
        lastName,
        account_id,
    ]);
    if (email) {
        await (0, account_creation_actions_1.default)(email, account_id);
    }
    await (0, account_creation_actions_1.creationActionsDone)(account_id);
}
exports["default"] = createAccount;
//# sourceMappingURL=create-account.js.map

/***/ }),

/***/ 497364:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const pool_1 = __importDefault(__webpack_require__(541808));
const parse_domain_1 = __webpack_require__(268040);
async function isDomainExclusiveSSO(email_address) {
    if (!email_address) {
        return;
    }
    const raw_domain = email_address.split("@")[1]?.trim().toLowerCase();
    if (!raw_domain) {
        return;
    }
    const exclusiveDomains = await getExclusiveDomains();
    if (exclusiveDomains.length == 0) {
        // For most servers, this is the case.
        return;
    }
    const parsed = (0, parse_domain_1.parseDomain)(raw_domain);
    if (parsed.type != parse_domain_1.ParseResultType.Listed) {
        // Domain not in the public suffix list
        return;
    }
    const { domain, topLevelDomains } = parsed;
    const canonical = [domain ?? "", ...topLevelDomains].join(".");
    if (exclusiveDomains.includes(canonical)) {
        return canonical;
    }
}
exports["default"] = isDomainExclusiveSSO;
async function getExclusiveDomains() {
    const pool = (0, pool_1.default)("minutes"); // exclusive sso is meant for a on prem settings where config RARELY changes.
    const { rows } = await pool.query("SELECT conf#>'{exclusive_domains}' as exclusive_domains FROM passport_settings");
    const v = [];
    for (const row of rows) {
        const { exclusive_domains } = row;
        if (exclusive_domains) {
            v.push(...exclusive_domains);
        }
    }
    return v;
}
//# sourceMappingURL=is-domain-exclusive-sso.js.map

/***/ }),

/***/ 437415:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


/*
Verify recaptcha or throw error on failure.

Does nothing if recaptcha is not configured on the server.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const server_settings_1 = __webpack_require__(526177);
const node_fetch_1 = __importDefault(__webpack_require__(978220));
async function reCaptcha(req) {
    const { re_captcha_v3_secret_key } = await (0, server_settings_1.getServerSettings)();
    if (!re_captcha_v3_secret_key)
        return;
    const { reCaptchaToken } = req.body;
    if (!reCaptchaToken) {
        throw Error("reCaptcha token must be provided");
    }
    // actually check it -- get the score via post request from google.
    const url = `https://www.google.com/recaptcha/api/siteverify?secret=${re_captcha_v3_secret_key}&response=${reCaptchaToken}&remoteip=${req.socket.remoteAddress}`;
    const response = await (0, node_fetch_1.default)(url);
    const result = await response.json();
    if (!result.success) {
        throw Error(`reCaptcha may be misconfigured. ${JSON.stringify(result["error-codes"])}`);
    }
    if (!result.score || result.score < 0.5) {
        throw Error("Only humans are allowed to use this feature.  Please try again.");
    }
}
exports["default"] = reCaptcha;
//# sourceMappingURL=recaptcha.js.map

/***/ }),

/***/ 99297:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const pool_1 = __importDefault(__webpack_require__(541808));
async function getRequiresTokens() {
    const pool = (0, pool_1.default)("long");
    const { rows } = await pool.query("SELECT EXISTS(SELECT 1 FROM registration_tokens WHERE disabled IS NOT true) AS have_tokens");
    return !!rows[0]?.have_tokens;
}
exports["default"] = getRequiresTokens;
//# sourceMappingURL=get-requires-token.js.map

/***/ }),

/***/ 14790:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


/* Redeem a registration token.

Raise an exception on failure with the error explaining the exception.

If no token is needed because of how site is configured,
then returns no matter what the input is.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const get_requires_token_1 = __importDefault(__webpack_require__(99297));
const pool_1 = __importDefault(__webpack_require__(541808));
async function redeem(token) {
    const required = await (0, get_requires_token_1.default)();
    if (!required) {
        // no token required, so nothing to do.
        return;
    }
    if (!token) {
        throw Error("no registration token provided");
    }
    const client = (0, pool_1.default)(); // no caching since the current count matters, etc.
    try {
        await client.query("BEGIN");
        // overview: first, we check if the token matches.
        // → check if it is disabled?
        // → check expiration date → abort if expired
        // → if counter, check counter vs. limit
        //   → true: increase the counter → ok
        //   → false: ok
        const q_match = `SELECT "expires", "counter", "limit", "disabled"
                     FROM registration_tokens
                     WHERE token = $1::TEXT
                     FOR UPDATE`;
        const match = await client.query(q_match, [token]);
        if (match.rows.length != 1) {
            throw Error("Registration token is wrong.");
        }
        // e.g. { expires: 2020-12-04T11:54:52.889Z, counter: null, limit: 10, disabled: ... }
        const { expires, counter: counter_raw, limit, disabled: disabled_raw, } = match.rows[0];
        const counter = counter_raw ?? 0;
        const disabled = disabled_raw ?? false;
        if (disabled) {
            throw Error("Registration token disabled.");
        }
        if (expires != null && expires.getTime() < new Date().getTime()) {
            throw Error("Registration token no longer valid.");
        }
        // we count in any case, but only enforce the limit if there is actually a limit set
        if (limit != null && limit <= counter) {
            throw Error("Registration token used up.");
        }
        else {
            // increase counter
            const q_inc = `UPDATE registration_tokens SET "counter" = coalesce("counter", 0) + 1
                     WHERE token = $1::TEXT`;
            await client.query(q_inc, [token]);
        }
        // all good, let's commit
        await client.query("COMMIT");
    }
    catch (err) {
        await client.query("ROLLBACK");
        throw err;
    }
}
exports["default"] = redeem;
//# sourceMappingURL=redeem.js.map

/***/ }),

/***/ 401696:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


/*
 *  This file is part of CoCalc: Copyright © 2021 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 }));
const smtp_1 = __importDefault(__webpack_require__(738182));
const sendgrid_1 = __importDefault(__webpack_require__(92500));
const throttle_1 = __importDefault(__webpack_require__(385094));
const server_settings_1 = __webpack_require__(526177);
async function sendEmail(message, account_id // account that we are sending this email *on behalf of*, if any (used for throttling).
) {
    await (0, throttle_1.default)(account_id);
    const { email_backend } = await (0, server_settings_1.getServerSettings)();
    switch (email_backend) {
        case "":
        case "none":
            throw Error(`no email backend configured`);
        case "smtp":
            return await (0, smtp_1.default)(message);
        case "sendgrid":
            return await (0, sendgrid_1.default)(message);
        default:
            throw Error(`no valid email backend configured: ${email_backend}`);
    }
}
exports["default"] = sendEmail;
//# sourceMappingURL=send-email.js.map

/***/ }),

/***/ 385094:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


/*
 *  This file is part of CoCalc: Copyright © 2021 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 }));
/*
Enforce limits on the number of that a user can cause to be sent.

For now starting with a simple limit: at most XXX messages per day.
*/
const DAILY_LIMIT = 1000;
const pii_1 = __webpack_require__(449376);
const pool_1 = __importDefault(__webpack_require__(541808));
const settings_1 = __webpack_require__(840336);
// Call this function whenever an email will be sent on behalf of the given account.
// It will increment a counter for each day, and if it goes too high it throws
// an exceptions, which prevents further emais from being sent for that user.
async function sendEmailThrottle(id // account_id or project_id or organization_id...
) {
    if (!id)
        return; // not associated to a particular user
    const day = startOfToday();
    // get current count
    const pool = (0, pool_1.default)("short"); // a few seconds old is ok...
    const { rows } = await pool.query("SELECT count FROM email_counter WHERE time=$1 AND id=$2", [day, id]);
    if (rows.length > 0 && rows[0].count > DAILY_LIMIT) {
        throw Error(`You may send at most ${DAILY_LIMIT} emails per day, and you have reached that limit.`);
    }
    // Increment the counter.
    if (rows.length > 0) {
        // This will always work with no race conditions, since the given entry exists.
        await pool.query("UPDATE email_counter SET count = count + 1 WHERE id=$1 AND time=$2", [id, day]);
    }
    else {
        const settings = await (0, settings_1.getServerSettings)();
        const expire = (0, pii_1.pii_retention_to_future)(settings.pii_retention ?? false);
        // It's possible another server created email_counter in the meantime,
        // hence the "ON CONFLICT".
        await pool.query("INSERT INTO email_counter (id,time,count,expire) VALUES($1,$2,1,$3) ON CONFLICT (id, time) DO UPDATE SET count = excluded.count + 1", [id, day, expire]);
    }
}
exports["default"] = sendEmailThrottle;
function startOfToday() {
    // https://stackoverflow.com/questions/7195513/how-do-you-get-the-unix-timestamp-for-the-start-of-today-in-javascript
    const now = new Date();
    return new Date(now.getFullYear(), now.getMonth(), now.getDate());
}
//# sourceMappingURL=throttle.js.map

/***/ }),

/***/ 837527:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getVerifyEmail = void 0;
const pool_1 = __importDefault(__webpack_require__(541808));
const random_key_1 = __webpack_require__(630900);
const site_url_1 = __importDefault(__webpack_require__(661348));
async function getVerifyEmail(email_address) {
    const token = await getToken(email_address);
    const site_url = await (0, site_url_1.default)();
    const url = `${site_url}/auth/verify/${token}?email=${encodeURIComponent(email_address)}`;
    return body(url);
}
exports.getVerifyEmail = getVerifyEmail;
async function getToken(email_address) {
    const pool = (0, pool_1.default)();
    const { rows } = await pool.query("SELECT account_id, email_address_challenge FROM accounts WHERE email_address=$1", [email_address]);
    if (rows.length == 0) {
        throw Error(`no account with email address "${email_address}"`);
    }
    const { account_id, email_address_challenge } = rows[0];
    if (email_address_challenge?.token &&
        email_address_challenge.email == email_address) {
        // return the same token if there is one for the same email
        return email_address_challenge.token;
    }
    const token = (0, random_key_1.generate)(16).toLowerCase();
    const data = { email: email_address, token, time: new Date() };
    await pool.query("UPDATE accounts SET email_address_challenge = $1::JSONB WHERE account_id = $2::UUID", [data, account_id]);
    return token;
}
function body(url) {
    const html = `
<p style="margin-top:0;margin-bottom:20px;">
<strong>
Please <a href="${url}">verify your email address</a>!
</strong>
</p>

<p style="margin-top:0;margin-bottom:20px;">
If the above link does not work, please copy and paste the following
URL into a new browser tab:
</p>

<pre style="margin-top:10px;margin-bottom:10px;font-size:11px;">
${url}
</pre>
`;
    const text = `
Please verify your email address by visiting the following URL in your web browser:

${url}

`;
    return { html, text };
}
//# sourceMappingURL=verify.js.map

/***/ }),

/***/ 508905:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


/*
Send a welcome email to a person if they create an account and
we know their email address.

Throws error if email address is not set for this use
in the database or if sending of email is not configured.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const send_email_1 = __importDefault(__webpack_require__(401696));
const settings_1 = __webpack_require__(840336);
const theme_1 = __webpack_require__(981975);
const verify_1 = __webpack_require__(837527);
const misc_1 = __webpack_require__(854006);
const site_url_1 = __importDefault(__webpack_require__(661348));
async function sendWelcomeEmail(email_address, account_id) {
    if (!(0, misc_1.is_valid_email_address)(email_address)) {
        throw Error("invalid email address");
    }
    const { text, html } = await getWelcomeEmail(email_address);
    await (0, send_email_1.default)({
        to: email_address,
        subject: "Welcome!",
        text,
        html,
        categories: ["welcome"],
        asm_group: 147985,
    }, account_id);
}
exports["default"] = sendWelcomeEmail;
async function getWelcomeEmail(email_address) {
    const verify = await (0, verify_1.getVerifyEmail)(email_address);
    const { help_email, site_name } = await (0, settings_1.getServerSettings)();
    const site_url = await (0, site_url_1.default)();
    const html = `\
<h1>Welcome to ${site_name}</h1>

<p style="margin-top:0;margin-bottom:10px;">
<a href="${site_url}">${site_name}</a> helps you to work with open-source scientific software in your web browser.
</p>

<p style="margin-top:0;margin-bottom:20px;">
You received this email because an account with the email address ${email_address} was created.
</p>

${verify.html}

<hr size="1"/>

<h3>Exploring ${site_name}</h3>
<p style="margin-top:0;margin-bottom:10px;">
In ${site_name} your work happens inside <strong>private projects</strong>.
These are personal workspaces which contain your files, computational worksheets, and data.
You can run your computations through the web interface, via interactive worksheets
and notebooks, or by executing a program in a terminal. ${site_name} supports
online editing of
    <a href="https://cocalc.com/features/jupyter-notebook">Jupyter Notebooks</a>,
    <a href="https://cocalc.com/features/sage">Sage Worksheets</a>,
    <a href="https://cocalc.com/features/latex-editor">LaTeX files</a>, etc.
</p>

<p style="margin-top:0;margin-bottom:10px;">
<strong>How to get from 0 to 100:</strong>
</p>

<ul>
<li style="margin-top:0;margin-bottom:10px;">
    <strong><a href="https://doc.cocalc.com/">CoCalc Manual:</a></strong> learn more about CoCalc's features.
</li>
<li style="margin-top:0;margin-bottom:10px;">
    <a href="https://doc.cocalc.com/jupyter.html">Working with Jupyter Notebooks</a>
</li>
<li style="margin-top:0;margin-bottom:10px;">
    <a href="https://doc.cocalc.com/sagews.html">Working with SageMath Worksheets</a>
</li>
<li style="margin-top:0;margin-bottom:10px;">
    <strong><a href="https://cocalc.com/policies/pricing.html">Subscriptions:</a></strong> make hosting more robust and increase project quotas
</li>
<li style="margin-top:0;margin-bottom:10px;">
    <a href="https://doc.cocalc.com/teaching-instructors.html">Teaching a course on CoCalc</a>.
</li>
<li style="margin-top:0;margin-bottom:10px;">
    <a href="https://doc.cocalc.com/howto/connectivity-issues.html">Troubleshooting connectivity issues</a>
</li>
<li style="margin-top:0;margin-bottom:10px;">
    <a href="https://github.com/sagemathinc/cocalc/wiki/MathematicalSyntaxErrors">Common mathematical syntax errors:</a> look into this if you are new to working with a programming language!
</li>
</ul>


<p style="margin-top:0;margin-bottom:20px;">
<strong>Collaboration:</strong>
You can invite collaborators to work with you inside a project.
Like you, they can edit the files in that project.
Edits are visible in <strong>real time</strong> for everyone online.
You can share your thoughts in a <strong>side chat</strong> next to each document.
</p>


<p><strong>Software:</strong>
<ul>
<li style="margin-top:0;margin-bottom:10px;">Mathematical Calculation:
    <a href="https://www.sagemath.org/">SageMath</a>,
    <a href="https://www.sympy.org/">SymPy</a>, etc.
</li>
<li style="margin-top:0;margin-bottom:10px;">Statistics and Data Science:
    <a href="https://www.r-project.org/">R project</a>,
    <a href="http://pandas.pydata.org/">Pandas</a>,
    <a href="http://www.statsmodels.org/">statsmodels</a>,
    <a href="http://scikit-learn.org/">scikit-learn</a>,
    <a href="http://www.nltk.org/">NLTK</a>, and <a href="https://cocalc.com/software">much more</a>.
</li>
<li style="margin-top:0;margin-bottom:10px;">Various other Computation:
    <a href="https://www.tensorflow.org/">Tensorflow</a>,
    <a href="https://cocalc.com/features/octave">Octave</a>,
    <a href="https://cocalc.com/features/julia">Julia</a>, etc.
</li>
</ul>

<p style="margin-top:0;margin-bottom:20px;">
Visit our <a href="https://cocalc.com/features">Feature Overview Page</a> for more details!
</p>


<p style="margin-top:20px;margin-bottom:10px;">
<strong>Questions?</strong>
</p>
<p style="margin-top:0;margin-bottom:10px;">
Schedule a Live Demo with a specialist from CoCalc.com: <a href="${theme_1.LIVE_DEMO_REQUEST}">request form</a>.
</p>
<p style="margin-top:0;margin-bottom:20px;">
In case of problems, concerns why you received this email, or other questions please contact:
<a href="mailto:${help_email}">${help_email}</a>.
</p>
`;
    const text = `
Welcome to ${site_name}!

${site_name} helps you to work with open-source scientific software in your web browser.

${site_url}

You received this email because an account with the email address ${email_address} was created.

${verify.text}

EXPLORING ${site_name}

In ${site_name} your work happens inside private projects.  These are personal
workspaces which contain your files, computational worksheets, and data.
You can run your computations through the web interface, via interactive worksheets
and notebooks, or by executing a program in a terminal. ${site_name} supports
online editing of Jupyter Notebooks, Sage Worksheets, LaTeX files, and much more.

HOW TO GET FROM 0 to 100:

CoCalc Manual: https://doc.cocalc.com/

Working with Jupyter Notebooks: https://doc.cocalc.com/jupyter.html

Working with SageMath Worksheets: https://doc.cocalc.com/sagews.html

Subscriptions: https://cocalc.com/policies/pricing.html

Teaching a course on CoCalc: https://doc.cocalc.com/teaching-instructors.html

Troubleshooting connectivity issues: https://doc.cocalc.com/howto/connectivity-issues.html

Common mathematical syntax errors: https://github.com/sagemathinc/cocalc/wiki/MathematicalSyntaxErrors

COLLABORATION

You can invite collaborators to work with you inside a project.
Like you, they can edit the files in that project.
Edits are visible in real time for everyone online.
You can share your thoughts in a side chat next to each document.

SOFTWARE

- Mathematical Calculation: https://www.sagemath.org, https://www.sympy.org, etc.

- Statistics and Data Science: https://www.r-project.org/, http://pandas.pydata.org/,
http://www.statsmodels.org/, http://scikit-learn.org/, http://www.nltk.org/, and
much more.  See https://cocalc.com/software

Various other Computation: https://www.tensorflow.org/, https://cocalc.com/features/octave,
https://cocalc.com/features/julia

Visit our Feature Overview Page at https://cocalc.com/features for more details!

QUESTIONS?

Schedule a Live Demo with a specialist from CoCalc.com:

${theme_1.LIVE_DEMO_REQUEST}

In case of problems, concerns why you received this email, or other questions
please contact ${help_email}.`;
    return { html, text };
}
//# sourceMappingURL=welcome-email.js.map

/***/ })

};
;

// load runtime
var __webpack_require__ = require("../../../../webpack-api-runtime.js");
__webpack_require__.C(exports);
var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
var __webpack_exports__ = __webpack_require__.X(0, [8180,2921,9557,5245,6652,6942,5517,2454,8220,884,1808,4006,8312,5710,4181,4557,7896,6177,8351,4988,3408,9022,6791], () => (__webpack_exec__(482260)));
module.exports = __webpack_exports__;

})();