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

/***/ 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");

/***/ }),

/***/ 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");

/***/ }),

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

module.exports = require("zlib");

/***/ }),

/***/ 26438:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "Z": () => (/* binding */ getParams)
/* harmony export */ });
function getParams(req) {
    if (req?.method == "POST") {
        return new Proxy({}, {
            get (_, key) {
                return req.body?.[key];
            }
        });
    /*
    // Disabled, since this could lead to a sneaky click on a link attack.
    // Should only be enabled for dev purposes.
    } else if (req?.method == "GET") {
    return new Proxy(
      {},
      {
        get(_, key) {
          if (typeof key != "string") {
            return undefined;
          }
          return req.query?.[key];
        },
      }
    );
*/ } else {
        // only support params for POST requests.
        return {};
    }
}


/***/ }),

/***/ 33539:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ passwordReset)
/* harmony export */ });
/* harmony import */ var _cocalc_server_auth_is_account_available__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(29459);
/* harmony import */ var _cocalc_server_auth_is_account_available__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_auth_is_account_available__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _cocalc_server_auth_password_reset__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(471936);
/* harmony import */ var _cocalc_server_auth_password_reset__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_auth_password_reset__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _cocalc_server_email_password_reset__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(97422);
/* harmony import */ var _cocalc_server_email_password_reset__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_cocalc_server_email_password_reset__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var lib_api_get_params__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(26438);
/*
 *  This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
 *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
 */ /*
Password reset works as follows:

1. Query the database to make sure there is a user with the given email address.
2. If a password reset was already sent within the last XX minutes,
   return an error -- we don't want people to spam other people with
   password resets.
3. Generate password reset token and write to database.
4. Send email.
5. Send response to user that email has been sent (or there was an error).
*/ 



async function passwordReset(req, res) {
    const { email  } = (0,lib_api_get_params__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Z)(req);
    let result;
    try {
        result = await handle(email?.toLowerCase(), req.ip);
    } catch (err) {
        result = {
            error: err.message
        };
    }
    res.json(result);
}
async function handle(email, ip) {
    if (await _cocalc_server_auth_is_account_available__WEBPACK_IMPORTED_MODULE_0___default()(email)) {
        // Bad -- email is *available*, which means no way to reset
        // the password for it, since it doesn't exist.
        return {
            error: `There is no account with email "${email}".`
        };
    }
    // Check that user isn't spamming email.
    const n = await (0,_cocalc_server_auth_password_reset__WEBPACK_IMPORTED_MODULE_1__.recentAttempts)(email, ip);
    if (n > 3) {
        return {
            error: `We recently sent multiple password resets for "${email}".  Check your email or wait a while and try later.`
        };
    }
    const id = await (0,_cocalc_server_auth_password_reset__WEBPACK_IMPORTED_MODULE_1__.createReset)(email, ip, 60 * 60 * 4); // 4 hour ttl seems reasonable for this.
    // TODO:
    // - Send email with the id and link
    // - Link should be back to next.js server (i.e., a new password reset target)
    // - Implement that target and backend handling of it.
    try {
        await _cocalc_server_email_password_reset__WEBPACK_IMPORTED_MODULE_2___default()(email, id);
    } catch (err) {
        console.trace(err);
        return {
            error: `Sending password reset email failed -- ${err.message}`
        };
    }
    return {
        success: `Password reset email successfully sent to ${email}.`
    };
}


/***/ }),

/***/ 471936:
/***/ (function(__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
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.createReset = exports.recentAttempts = void 0;
const uuid_1 = __webpack_require__(509557);
const pool_1 = __importDefault(__webpack_require__(541808));
const util_1 = __webpack_require__(258813);
// Returns number of "recent" attempts to reset the password with this
// email from this ip address. By "recent" we mean, "in the last 10 minutes".
async function recentAttempts(email_address, ip_address) {
    const pool = (0, pool_1.default)();
    const { rows } = await pool.query("SELECT COUNT(*)::INT FROM password_reset_attempts WHERE email_address=$1 AND ip_address=$2 AND time >= NOW() - INTERVAL '10 min'", [email_address, ip_address]);
    return rows[0].count;
}
exports.recentAttempts = recentAttempts;
async function createReset(email_address, ip_address, ttl_s) {
    const pool = (0, pool_1.default)();
    // Record that there was an attempt:
    if (ip_address) {
        await pool.query("INSERT INTO password_reset_attempts(id, email_address,ip_address,time,expire) VALUES($1::UUID,$2::TEXT,$3,NOW(),NOW() + INTERVAL '1 day')", [(0, uuid_1.v4)(), email_address, ip_address]);
    }
    // Create the expiring password reset token:
    const id = (0, uuid_1.v4)();
    await pool.query("INSERT INTO password_reset(id,email_address,expire) VALUES($1::UUID,$2::TEXT,$3::TIMESTAMP)", [id, email_address, (0, util_1.expireTime)(ttl_s)]);
    return id;
}
exports.createReset = createReset;
//# sourceMappingURL=password-reset.js.map

/***/ }),

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


/* Send a password reset email */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const site_url_1 = __importDefault(__webpack_require__(661348));
const smtp_1 = __importDefault(__webpack_require__(738182));
const sendgrid_1 = __importDefault(__webpack_require__(92500));
const settings_1 = __webpack_require__(840336);
async function sendPasswordResetEmail(email_address, // target email_address of user who will receive the password reset email
id // the secret code that they must supply to reset their password
) {
    const subject = "Password Reset";
    const { html, text } = await getMessage(email_address, id);
    const message = { to: email_address, subject, html, text };
    try {
        await (0, smtp_1.default)(message, "password_reset");
    }
    catch (err) {
        console.log(`sending password reset via secondary smtp server failed; trying sendgrid -- ${err}`);
        await (0, sendgrid_1.default)(message);
    }
}
exports["default"] = sendPasswordResetEmail;
async function getMessage(email_address, id) {
    const { help_email, site_name } = await (0, settings_1.getServerSettings)();
    const site_url = await (0, site_url_1.default)();
    const reset_url = `${site_url}/auth/password-reset/${id}`;
    let html = `
<div>
Hello,
<br/>
<br/>
Somebody just requested to change the password of your ${site_name ?? "OpenCoCalc"} account with email address <b>${email_address}</b>.
If you requested this password change, please click this link:
<div style="text-align: center; font-size: 120%; margin:30px 0">
  <b><a href="${reset_url}">${reset_url}</a></b>
</div>
<br/>
If you don't want to change your password, ignore this message.
`;
    if (help_email) {
        html += `
<br/>
<br/>
In case of problems, email
<a href="mailto:${help_email}">${help_email}</a>.
`;
    }
    let text = `
Hello,

Somebody just requested to change the password of your
${site_name ?? "OpenCoCalc"} account with email address ${email_address}.

If you requested this password change, visit this URL:

    ${reset_url}

If you don't want to change your password, ignore this message.
`;
    if (help_email) {
        text += `\n\nIn case of problems, email ${help_email}.\n`;
    }
    return { html, text };
}
//# sourceMappingURL=password-reset.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,6652,6942,5517,2454,1808,4006,8312,4181,4557,7896,6177,9022], () => (__webpack_exec__(33539)));
module.exports = __webpack_exports__;

})();