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

/***/ }),

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

/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "Z": () => (/* binding */ isPost)
/* harmony export */ });
function isPost(req, res) {
    if ((req === null || req === void 0 ? void 0 : req.method) !== "POST") {
        res === null || res === void 0 ? void 0 : res.status(404).json({
            message: "must use a POST request"
        });
        return false;
    }
    return true;
};


/***/ }),

/***/ 530057:
/***/ ((__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_is_post__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(447618);
/*
 *  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) {
    if (!(0,lib_api_is_post__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Z)(req, res)) return;
    const { email  } = req.body;
    const result = await handle(email, req.ip);
    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 > 1) {
        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) {
        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__) {


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 }));
exports.createReset = exports.recentAttempts = void 0;
var uuid_1 = __webpack_require__(282185);
var pool_1 = __importDefault(__webpack_require__(541808));
var 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".
function recentAttempts(email_address, ip_address) {
    return __awaiter(this, void 0, void 0, function () {
        var pool, rows;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    pool = (0, pool_1.default)();
                    return [4 /*yield*/, 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])];
                case 1:
                    rows = (_a.sent()).rows;
                    return [2 /*return*/, rows[0].count];
            }
        });
    });
}
exports.recentAttempts = recentAttempts;
function createReset(email_address, ip_address, ttl_s) {
    return __awaiter(this, void 0, void 0, function () {
        var pool, id;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    pool = (0, pool_1.default)();
                    if (!ip_address) return [3 /*break*/, 2];
                    return [4 /*yield*/, pool.query("INSERT INTO password_reset_attempts(id, email_address,ip_address,time) VALUES($1::UUID,$2::TEXT,$3,NOW())", [(0, uuid_1.v4)(), email_address, ip_address])];
                case 1:
                    _a.sent();
                    _a.label = 2;
                case 2:
                    id = (0, uuid_1.v4)();
                    return [4 /*yield*/, 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)])];
                case 3:
                    _a.sent();
                    return [2 /*return*/, id];
            }
        });
    });
}
exports.createReset = createReset;
//# sourceMappingURL=password-reset.js.map

/***/ }),

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


/* Send a password reset email */
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 }));
var site_url_1 = __importDefault(__webpack_require__(661348));
var smtp_1 = __importDefault(__webpack_require__(738182));
var sendgrid_1 = __importDefault(__webpack_require__(92500));
var settings_1 = __webpack_require__(840336);
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
) {
    return __awaiter(this, void 0, void 0, function () {
        var subject, _a, html, text, message, err_1;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    subject = "Password Reset";
                    return [4 /*yield*/, getMessage(email_address, id)];
                case 1:
                    _a = _b.sent(), html = _a.html, text = _a.text;
                    message = { to: email_address, subject: subject, html: html, text: text };
                    _b.label = 2;
                case 2:
                    _b.trys.push([2, 4, , 6]);
                    return [4 /*yield*/, (0, smtp_1.default)(message, "password_reset")];
                case 3:
                    _b.sent();
                    return [3 /*break*/, 6];
                case 4:
                    err_1 = _b.sent();
                    console.log("sending password reset via secondary smtp server failed; trying sendgrid.", err_1);
                    return [4 /*yield*/, (0, sendgrid_1.default)(message)];
                case 5:
                    _b.sent();
                    return [3 /*break*/, 6];
                case 6: return [2 /*return*/];
            }
        });
    });
}
exports["default"] = sendPasswordResetEmail;
function getMessage(email_address, id) {
    return __awaiter(this, void 0, void 0, function () {
        var _a, help_email, site_name, site_url, reset_url, html, text;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, (0, settings_1.getServerSettings)()];
                case 1:
                    _a = _b.sent(), help_email = _a.help_email, site_name = _a.site_name;
                    return [4 /*yield*/, (0, site_url_1.default)()];
                case 2:
                    site_url = _b.sent();
                    reset_url = "".concat(site_url, "/auth/password-reset/").concat(id);
                    html = "\n<div>\nHello,\n<br/>\n<br/>\nSomebody just requested to change the password of your ".concat(site_name !== null && site_name !== void 0 ? site_name : "OpenCoCalc", " account with email address <b>").concat(email_address, "</b>.\nIf you requested this password change, please click this link:\n<div style=\"text-align: center; font-size: 120%; margin:30px 0\">\n  <b><a href=\"").concat(reset_url, "\">").concat(reset_url, "</a></b>\n</div>\n<br/>\nIf you don't want to change your password, ignore this message.\n");
                    if (help_email) {
                        html += "\n<br/>\n<br/>\nIn case of problems, email\n<a href=\"mailto:".concat(help_email, "\">").concat(help_email, "</a>.\n");
                    }
                    text = "\nHello,\n\nSomebody just requested to change the password of your\n".concat(site_name !== null && site_name !== void 0 ? site_name : "OpenCoCalc", " account with email address ").concat(email_address, ".\n\nIf you requested this password change, visit this URL:\n\n    ").concat(reset_url, "\n\nIf you don't want to change your password, ignore this message.\n");
                    if (help_email) {
                        text += "\n\nIn case of problems, email ".concat(help_email, ".\n");
                    }
                    return [2 /*return*/, { html: html, text: 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,2185,6652,6942,2454,1808,9738,8312,8416,4181,5016,6177,1348,9022], () => (__webpack_exec__(530057)));
module.exports = __webpack_exports__;

})();