Use jst_server.Problem everywhere, make /_lib/post_request.jst use jst_server's new...
[ndcode_site.git] / api / account / password_reset.json.jst
1 let crypto = require('crypto')
2 let jst_server = (await import('@ndcode/jst_server')).default
3 let XDate = require('xdate')
4
5 return async env => {
6   let get_nodemailer = await _require('/_lib/get_nodemailer.jst')
7   let post_request = await _require('/_lib/post_request.jst')
8
9   await post_request(
10     // env
11     env,
12     // handler
13     async (email, password) => {
14       // coerce and/or validate
15       email = email.slice(0, 256).toLowerCase()
16       password = password.slice(0, 256)
17       if (email.length === 0 || password.length < 8)
18         throw new jst_server.Problem(
19           'Bad request',
20           'Minimum length check failed',
21           400
22         )
23
24       let transaction = await env.site.database.Transaction()
25       let link_code
26       let nodemailer
27       let noreply_from, noreply_signature
28       let given_names, family_name
29       try {
30         let root = await transaction.get({})
31         let accounts = await root.get('accounts', {})
32         let account = await accounts.get(email)
33         if (account === undefined)
34           throw new jst_server.Problem(
35             'Account does not exist',
36             `Please create the account for "${email}" before attempting to reset its password.`
37             421
38           )
39
40         link_code = crypto.randomBytes(16).toString('hex')
41         let expires = new XDate()
42         expires.addDays(1)
43         account.set_json(
44           'verify_password',
45           {password, link_code, expires: expires.getTime()}
46         )
47
48         nodemailer = await get_nodemailer(root, 'noreply')
49
50         let globals = await root.get('globals', {})
51         site_url = await globals.get_json('site_url')
52         noreply_from = await globals.get_json('noreply_from')
53         noreply_signature = await globals.get_json('noreply_signature')
54
55         given_names = await account.get_json('given_names', '')
56         family_name = await account.get_json('family_name', '')
57
58         await transaction.commit()
59       }
60       catch (error) {
61         transaction.rollback()
62         throw error
63       }
64
65       let name =
66         family_name.length ? `${given_names} ${family_name}` : given_names
67       await nodemailer.sendMail(
68         {
69           from: noreply_from,
70           to: `${name} <${email}>`,
71           subject: 'Password reset',
72           text: `Dear ${given_names},
73
74 We have received a request to reset the account password for your email address.
75
76 If this request is valid, please verify the new password by visiting the below link:
77 ${site_url}/my_account/verify_password/index.html?email=${encodeURIComponent(email)}&link_code=${encodeURIComponent(link_code)}
78
79 The link is valid for 24 hours.
80
81 Thanks,
82 ${noreply_signature}
83 `
84         }
85       )
86     }
87   )
88 }