providing password reset services for a long while: circa 2025

feat: add full password reset flow

+90
+14
features/command.ts
··· 32 32 }, 33 33 }, 34 34 { 35 + type: "actions", 36 + elements: [ 37 + { 38 + type: "button", 39 + text: { 40 + type: "plain_text", 41 + text: "Reset Password", 42 + }, 43 + action_id: "reset-password", 44 + style: "danger", 45 + }, 46 + ], 47 + }, 48 + { 35 49 type: "context", 36 50 elements: [ 37 51 {
+1
features/index.ts
··· 1 1 export { default as command } from "./command"; 2 2 export { default as signup } from "./signup"; 3 + export { default as resetPassword } from "./reset-password";
+75
features/reset-password.ts
··· 1 + import { slackApp } from "../index"; 2 + 3 + const resetPassword = async () => { 4 + slackApp.action("reset-password", async ({ context }) => { 5 + if (!context?.respond) return; 6 + 7 + const user = ( 8 + await context.client.users.info({ user: context.userId as string }) 9 + ).user; 10 + 11 + if (!user) return; 12 + 13 + const reset: { user_id: string; reset_token: string } = await fetch( 14 + "https://waka.hackclub.com/reset-password", 15 + { 16 + method: "POST", 17 + headers: { 18 + Authorization: `Bearer ${process.env.HACKATIME_API_KEY}`, 19 + }, 20 + body: new URLSearchParams({ 21 + email: user.profile?.email || "", 22 + }), 23 + }, 24 + ).then((res) => res.json()); 25 + 26 + if (reset.user_id !== context.userId) 27 + await context.respond({ 28 + response_type: "ephemeral", 29 + text: "uh oh! something went wrong :ohnoes:", 30 + blocks: [ 31 + { 32 + type: "section", 33 + text: { 34 + type: "mrkdwn", 35 + text: "uh oh! something went wrong :ohnoes:", 36 + }, 37 + }, 38 + { 39 + type: "context", 40 + elements: [ 41 + { 42 + type: "mrkdwn", 43 + text: `if this keeps happening dm <@U062UG485EE> and let them know \`${user.profile?.email}\` doesn't exist`, 44 + }, 45 + ], 46 + }, 47 + ], 48 + }); 49 + 50 + await context.respond({ 51 + response_type: "ephemeral", 52 + text: "great! I generated a link to reset your password :yay:", 53 + blocks: [ 54 + { 55 + type: "section", 56 + text: { 57 + type: "mrkdwn", 58 + text: "great! I generated a link to reset your password :yay:", 59 + }, 60 + }, 61 + { 62 + type: "context", 63 + elements: [ 64 + { 65 + type: "mrkdwn", 66 + text: `reset link: \`https://waka.hackclub.com/set-password?token=${reset.reset_token}\``, 67 + }, 68 + ], 69 + }, 70 + ], 71 + }); 72 + }); 73 + }; 74 + 75 + export default resetPassword;