content: package org.airsonic.player.controller;
  
  import de.triology.recaptchav2java.ReCaptcha;
  import org.airsonic.player.domain.User;
  import org.airsonic.player.service.SecurityService;
  import org.airsonic.player.service.SettingsService;
  import org.apache.commons.lang.StringUtils;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RequestMethod;
  import org.springframework.web.servlet.ModelAndView;
  
  import javax.mail.Message;
  import javax.mail.Session;
  import javax.mail.Transport;
  import javax.mail.internet.InternetAddress;
  import javax.mail.internet.MimeMessage;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import java.security.SecureRandom;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Properties;
  
  /**
   * Spring MVC Controller that serves the login page.
   */
  @Controller
  @RequestMapping("/recover")
  public class RecoverController {
  
  
      private static final Logger LOG = LoggerFactory.getLogger(RecoverController.class);
  
      private static final String SYMBOLS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
      private final SecureRandom random = new SecureRandom();
      private static final int PASSWORD_LENGTH = 32;
  
      @Autowired
      private SettingsService settingsService;
      @Autowired
      private SecurityService securityService;
  
      @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
      public ModelAndView recover(HttpServletRequest request, HttpServletResponse response) {
  
          Map<String, Object> map = new HashMap<String, Object>();
          String usernameOrEmail = StringUtils.trimToNull(request.getParameter("usernameOrEmail"));
  
          if (usernameOrEmail != null) {
  
              map.put("usernameOrEmail", usernameOrEmail);
              User user = getUserByUsernameOrEmail(usernameOrEmail);
  
              boolean captchaOk;
              if (settingsService.isCaptchaEnabled()) {
                  String recaptchaResponse = request.getParameter("g-recaptcha-response");
                  ReCaptcha captcha = new ReCaptcha(settingsService.getRecaptchaSecretKey());
                  captchaOk = recaptchaResponse != null && captcha.isValid(recaptchaResponse);
              } else {
                  captchaOk = true;
              }
  
              if (!captchaOk) {
                  map.put("error", "recover.error.invalidcaptcha");
              } else if (user == null) {
                  map.put("error", "recover.error.usernotfound");
              } else if (user.getEmail() == null) {
                  map.put("error", "recover.error.noemail");
              } else {
                  StringBuilder sb = new StringBuilder(PASSWORD_LENGTH);
                  for (int i = 0; i < PASSWORD_LENGTH; i++) {
                      int index = random.nextInt(SYMBOLS.length());
                      sb.append(SYMBOLS.charAt(index));
                  }
                  String password = sb.toString();
  
                  if (emailPassword(password, user.getUsername(), user.getEmail())) {
                      map.put("sentTo", user.getEmail());
                      user.setLdapAuthenticated(false);
                      user.setPassword(password);
                      securityService.updateUser(user);
                  } else {
                      map.put("error", "recover.error.sendfailed");
                  }
              }
          }
  
          if (settingsService.isCaptchaEnabled()) {
              map.put("recaptchaSiteKey", settingsService.getRecaptchaSiteKey());
          }
  
          return new ModelAndView("recover", "model", map);
      }
  
      private User getUserByUsernameOrEmail(String usernameOrEmail) {
          if (usernameOrEmail != null) {
              User user = securityService.getUserByName(usernameOrEmail);
              if (user != null) {
                  return user;
              }
              return securityService.getUserByEmail(usernameOrEmail);
          }
          return null;
      }
  
      /*
      * e-mail user new password via configured Smtp server
      */
      private boolean emailPassword(String password, String username, String email) {
          /* Default to protocol smtp when SmtpEncryption is set to "None" */
          String prot = "smtp";
  
          if (settingsService.getSmtpServer() == null || settingsService.getSmtpServer().isEmpty()) {
              LOG.warn("Can not send email; no Smtp server configured.");
              return false;
          }
  
          Properties props = new Properties();
          if (settingsService.getSmtpEncryption().equals("SSL/TLS")) {
              prot = "smtps";
              props.put("mail." + prot + ".ssl.enable", "true");
          } else if (settingsService.getSmtpEncryption().equals("STARTTLS")) {
              prot = "smtp";
              props.put("mail." + prot + ".starttls.enable", "true");
          }
          props.put("mail." + prot + ".host", settingsService.getSmtpServer());
          props.put("mail." + prot + ".port", settingsService.getSmtpPort());
          /* use authentication when SmtpUser is configured */
          if (settingsService.getSmtpUser() != null && !settingsService.getSmtpUser().isEmpty()) {
              props.put("mail." + prot + ".auth", "true");
          }
  
          Session session = Session.getInstance(props, null);
  
          try {
              Message message = new MimeMessage(session);
              message.setFrom(new InternetAddress(settingsService.getSmtpFrom()));
              message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email));
              message.setSubject("Airsonic Password");
              message.setText("Hi there!\n\n" +
                      "You have requested to reset your Airsonic password.  Please find your new login details below.\n\n" +
                      "Username: " + username + "\n" +
                      "Password: " + password + "\n\n" +
                      "--\n" +
                      "Your Airsonic server\n" +
                      "airsonic.github.io/");
              message.setSentDate(new Date());
  
              Transport trans = session.getTransport(prot);
              try {
                  if (props.get("mail." + prot + ".auth") != null && props.get("mail." + prot + ".auth").equals("true")) {
                      trans.connect(settingsService.getSmtpServer(), settingsService.getSmtpUser(), settingsService.getSmtpPassword());
                  } else {
                      trans.connect();
                  }
                  trans.sendMessage(message, message.getAllRecipients());
              } finally {
                  trans.close();
              }
              return true;
  
          } catch (Exception x) {
              LOG.warn("Failed to send email.", x);
              return false;
          }
      }
  
  }
  