Project/codestates-final-project

리펙토링 및 개선 - 7 / nodemailer를 이용한 비밀번호 재발급

fullfish 2022. 6. 8. 21:14

현재의 문제점

현재 user의 password는 Bcrypt에 의해 hashing되어져서 보관되고 있으므로

복호화가 불가능하다

그래서 user가 password를 잊어먹었을 경우에는 찾을 방법이 없다

만약에 mysql에서 password를 직접적으로 바꾼다고 하더라도

로그인시 digest와 검증하게끔 로직이 이루어져 있기에 안된다

 

그렇기에 많은 사이트들이 비밀번호찾기시 비밀번호를 알려주는것이 아닌

이메일로 임시 비밀번호를 발급해주거나,

새비밀번호를 생성하는것이 아닌가 싶다

 

해결법

nodemailer를 이용해서 임시비밀번호를 email로 보내준다

(원래 EmailJS를 쓰려고 했으나 nodemailer로 바꿈)

nodemailer에 대해서 내가 쓴 글

코드

메인 코드

find: {
    post: async (req, res) => {
      try {
        const email = req.body.email;
        const userInfo = await user.findOne({
          where: { email },
        });
        if (!userInfo) {
          return res.status(400).send({ message: "no email" });
        } else {
          const newPassword = createRandomPassword();
          nodemailer.sendEmail(email, newPassword, "임시 비밀번호");
          bcrypt.genSalt(13, async function (err, salt) {
            bcrypt.hash(newPassword, salt, async function (err, hash) {
              await user.update({ password: hash }, { where: { id: userInfo.id } });
              await slack.slack("sign/find Post 200", `id : ${userInfo.id}`);
              return res.status(200).send({ data: { id: userInfo.id } });
            });
          });
        }
      } catch (err) {
        await slack.slack("sign/find Post 501");
        res.status(501).send("sign/find Post");
      }
    },
  },

nodemailer.sendEmail() 함수 코드

const nodemailer = require("nodemailer");
const smtpTransporter = require("nodemailer-smtp-transport");

exports.sendEmail = (email, newPassword, subject) => {
  //이메일 보내기
  var smtpTransport = nodemailer.createTransport(
    smtpTransporter({
      service: "Naver",
      host: "smtp.naver.com",
      auth: {
        user: process.env.NAVER_EMAIL, //보내는 분의 메일계정
        pass: process.env.NAVER_PASSWORD,
      },
    })
  );

  var mailOption = {
    from: process.env.NAVER_EMAIL, // 보내는 분의 메일계정
    to: email, // 받는 분의 메일계정 (여러 개 가능)
    subject: subject,
    html:
      `<h1>${subject} : ${newPassword}</h1>` +
      `<h3><div>저희 프로젝트의 Git 레포입니다</div> <div>아래 이미지를 눌러주세요</div></h3><a href="https://github.com/codestates/just-moment-trip">` +
      '<img src="https://user-images.githubusercontent.com/89363516/165240860-f200568c-6e65-4c88-ab04-d2789e29c8f1.png" height="250" width="250"/></p></a>',
  };

  smtpTransport.sendMail(mailOption, (err, response) => {
    // 메일을 보내는 코드
    if (err) {
      console.log(err);
      throw err;
    }
  });
};

createRandomPassword()의 코드

function createRandomPassword() {
  const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  const number = "0123456789";
  const special = "!@#%^&*()_-+=}[]`~:;>,.?";
  const random = "abc";
  let newPassword = "";
  let a = Math.ceil(Math.random() * 3) + 3,
    b = Math.ceil(Math.random() * 3) + 3;
  c = Math.ceil(Math.random() * 3) + 3;
  while (a + b + c >= 1) {
    const select = random[Math.floor(Math.random() * random.length)];
    if (select === "a" && a !== 0) {
      newPassword += alphabet[Math.floor(Math.random() * alphabet.length)];
      a--;
    } else if (select === "b" && b !== 0) {
      newPassword += number[Math.floor(Math.random() * number.length)];
      b--;
    } else if (select === "c" && c !== 0) {
      newPassword += special[Math.floor(Math.random() * special.length)];
      c--;
    }
  }
  return newPassword;
}

비밀번호를 최대한 랜덤하게 생성하기위해서

알파벳, 숫자, 특수문자를 섞었으며 순서와 길이도 항상 다르게 만들었다.

정확히는 모르겠는데 특수문자에서 '$', '<', '{'이것 3가지가 에러를 내는것으로 보여서 뺐다

(db에는 찍히는데 메일로는 안올때가 있음
예를들어

db : '25Cm6{:33;;PH<p, 일 때,

메일 : 25Cm6{:33;;PH

db : 5*FOtLa321c36){<? 일 때,

메일 : 5*FOtLa321c36){

 

예시