Merge remote-tracking branch 'origin/pr/774'

Signed-off-by: Andrew DeMaria <lostonamountain@gmail.com>
master
Andrew DeMaria 6 years ago
commit c56416a9ca
No known key found for this signature in database
GPG Key ID: 0A3F5E91F8364EDF
  1. 12
      airsonic-main/pom.xml
  2. 28
      airsonic-main/src/main/java/org/airsonic/player/command/AdvancedSettingsCommand.java
  3. 9
      airsonic-main/src/main/java/org/airsonic/player/controller/AdvancedSettingsController.java
  4. 26
      airsonic-main/src/main/java/org/airsonic/player/controller/RecoverController.java
  5. 32
      airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java
  6. 9
      airsonic-main/src/main/resources/org/airsonic/player/i18n/ResourceBundle_en.properties
  7. 29
      airsonic-main/src/main/webapp/WEB-INF/jsp/advancedSettings.jsp
  8. 5
      airsonic-main/src/main/webapp/WEB-INF/jsp/recover.jsp
  9. BIN
      repo/net/tanesha/recaptcha4j/recaptcha4j/0.0.8/recaptcha4j-0.0.8-sources.jar
  10. BIN
      repo/net/tanesha/recaptcha4j/recaptcha4j/0.0.8/recaptcha4j-0.0.8.jar
  11. 6
      repo/net/tanesha/recaptcha4j/recaptcha4j/0.0.8/recaptcha4j-0.0.8.pom

@ -323,18 +323,18 @@
<version>1.1.0</version> <version>1.1.0</version>
</dependency> </dependency>
<dependency>
<groupId>net.tanesha.recaptcha4j</groupId>
<artifactId>recaptcha4j</artifactId>
<version>0.0.8</version>
</dependency>
<dependency> <dependency>
<groupId>de.u-mass</groupId> <groupId>de.u-mass</groupId>
<artifactId>lastfm-java</artifactId> <artifactId>lastfm-java</artifactId>
<version>0.1.2</version> <version>0.1.2</version>
</dependency> </dependency>
<dependency>
<groupId>de.triology.recaptchav2-java</groupId>
<artifactId>recaptchav2-java</artifactId>
<version>1.0.2</version>
</dependency>
<!-- SONOS API / WSDL SUPPORT --> <!-- SONOS API / WSDL SUPPORT -->
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>

@ -45,6 +45,10 @@ public class AdvancedSettingsCommand {
private String smtpPassword; private String smtpPassword;
private String smtpFrom; private String smtpFrom;
private boolean captchaEnabled;
private String recaptchaSiteKey;
private String recaptchaSecretKey;
public String getDownloadLimit() { public String getDownloadLimit() {
return downloadLimit; return downloadLimit;
} }
@ -167,4 +171,28 @@ public class AdvancedSettingsCommand {
public void setSmtpFrom(String smtpFrom) { public void setSmtpFrom(String smtpFrom) {
this.smtpFrom = smtpFrom; this.smtpFrom = smtpFrom;
} }
public boolean isCaptchaEnabled() {
return captchaEnabled;
}
public void setCaptchaEnabled(boolean captchaEnabled) {
this.captchaEnabled = captchaEnabled;
}
public String getRecaptchaSiteKey() {
return recaptchaSiteKey;
}
public void setRecaptchaSiteKey(String recaptchaSiteKey) {
this.recaptchaSiteKey = recaptchaSiteKey;
}
public String getRecaptchaSecretKey() {
return recaptchaSecretKey;
}
public void setRecaptchaSecretKey(String recaptchaSecretKey) {
this.recaptchaSecretKey = recaptchaSecretKey;
}
} }

@ -61,6 +61,9 @@ public class AdvancedSettingsController {
command.setSmtpUser(settingsService.getSmtpUser()); command.setSmtpUser(settingsService.getSmtpUser());
command.setSmtpFrom(settingsService.getSmtpFrom()); command.setSmtpFrom(settingsService.getSmtpFrom());
command.setCaptchaEnabled(settingsService.isCaptchaEnabled());
command.setRecaptchaSiteKey(settingsService.getRecaptchaSiteKey());
model.addAttribute("command", command); model.addAttribute("command", command);
return "advancedSettings"; return "advancedSettings";
} }
@ -98,6 +101,12 @@ public class AdvancedSettingsController {
settingsService.setSmtpPassword(command.getSmtpPassword()); settingsService.setSmtpPassword(command.getSmtpPassword());
} }
settingsService.setCaptchaEnabled(command.isCaptchaEnabled());
settingsService.setRecaptchaSiteKey(command.getRecaptchaSiteKey());
if (StringUtils.isNotEmpty(command.getRecaptchaSecretKey())) {
settingsService.setRecaptchaSecretKey(command.getRecaptchaSecretKey());
}
settingsService.save(); settingsService.save();
return "redirect:advancedSettings.view"; return "redirect:advancedSettings.view";

@ -1,8 +1,6 @@
package org.airsonic.player.controller; package org.airsonic.player.controller;
import net.tanesha.recaptcha.ReCaptcha; import de.triology.recaptchav2java.ReCaptcha;
import net.tanesha.recaptcha.ReCaptchaFactory;
import net.tanesha.recaptcha.ReCaptchaResponse;
import org.airsonic.player.domain.User; import org.airsonic.player.domain.User;
import org.airsonic.player.service.SecurityService; import org.airsonic.player.service.SecurityService;
import org.airsonic.player.service.SettingsService; import org.airsonic.player.service.SettingsService;
@ -49,19 +47,22 @@ public class RecoverController {
Map<String, Object> map = new HashMap<String, Object>(); Map<String, Object> map = new HashMap<String, Object>();
String usernameOrEmail = StringUtils.trimToNull(request.getParameter("usernameOrEmail")); String usernameOrEmail = StringUtils.trimToNull(request.getParameter("usernameOrEmail"));
ReCaptcha captcha = ReCaptchaFactory.newSecureReCaptcha("6LcZ3OMSAAAAANkKMdFdaNopWu9iS03V-nLOuoiH",
"6LcZ3OMSAAAAAPaFg89mEzs-Ft0fIu7wxfKtkwmQ", false);
boolean showCaptcha = true;
if (usernameOrEmail != null) { if (usernameOrEmail != null) {
map.put("usernameOrEmail", usernameOrEmail); map.put("usernameOrEmail", usernameOrEmail);
User user = getUserByUsernameOrEmail(usernameOrEmail); User user = getUserByUsernameOrEmail(usernameOrEmail);
String challenge = request.getParameter("recaptcha_challenge_field");
String uresponse = request.getParameter("recaptcha_response_field");
ReCaptchaResponse captchaResponse = captcha.checkAnswer(request.getRemoteAddr(), challenge, uresponse);
if (!captchaResponse.isValid()) { 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"); map.put("error", "recover.error.invalidcaptcha");
} else if (user == null) { } else if (user == null) {
map.put("error", "recover.error.usernotfound"); map.put("error", "recover.error.usernotfound");
@ -74,15 +75,14 @@ public class RecoverController {
user.setLdapAuthenticated(false); user.setLdapAuthenticated(false);
user.setPassword(password); user.setPassword(password);
securityService.updateUser(user); securityService.updateUser(user);
showCaptcha = false;
} else { } else {
map.put("error", "recover.error.sendfailed"); map.put("error", "recover.error.sendfailed");
} }
} }
} }
if (showCaptcha) { if (settingsService.isCaptchaEnabled()) {
map.put("captcha", captcha.createRecaptchaHtml(null, null)); map.put("recaptchaSiteKey", settingsService.getRecaptchaSiteKey());
} }
return new ModelAndView("recover", "model", map); return new ModelAndView("recover", "model", map);

@ -117,6 +117,10 @@ public class SettingsService {
private static final String KEY_IGNORE_SYMLINKS = "IgnoreSymLinks"; private static final String KEY_IGNORE_SYMLINKS = "IgnoreSymLinks";
private static final String KEY_EXCLUDE_PATTERN_STRING = "ExcludePattern"; private static final String KEY_EXCLUDE_PATTERN_STRING = "ExcludePattern";
private static final String KEY_CAPTCHA_ENABLED = "CaptchaEnabled";
private static final String KEY_RECAPTCHA_SITE_KEY = "ReCaptchaSiteKey";
private static final String KEY_RECAPTCHA_SECRET_KEY = "ReCaptchaSecretKey";
// Database Settings // Database Settings
private static final String KEY_DATABASE_CONFIG_TYPE = "DatabaseConfigType"; private static final String KEY_DATABASE_CONFIG_TYPE = "DatabaseConfigType";
private static final String KEY_DATABASE_CONFIG_EMBED_DRIVER = "DatabaseConfigEmbedDriver"; private static final String KEY_DATABASE_CONFIG_EMBED_DRIVER = "DatabaseConfigEmbedDriver";
@ -193,6 +197,10 @@ public class SettingsService {
private static final String DEFAULT_SMTP_PASSWORD = null; private static final String DEFAULT_SMTP_PASSWORD = null;
private static final String DEFAULT_SMTP_FROM = "airsonic@airsonic.org"; private static final String DEFAULT_SMTP_FROM = "airsonic@airsonic.org";
private static final boolean DEFAULT_CAPTCHA_ENABLED = false;
private static final String DEFAULT_RECAPTCHA_SITE_KEY = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI";
private static final String DEFAULT_RECAPTCHA_SECRET_KEY = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe";
private static final DataSourceConfigType DEFAULT_DATABASE_CONFIG_TYPE = DataSourceConfigType.LEGACY; private static final DataSourceConfigType DEFAULT_DATABASE_CONFIG_TYPE = DataSourceConfigType.LEGACY;
private static final String DEFAULT_DATABASE_CONFIG_EMBED_DRIVER = null; private static final String DEFAULT_DATABASE_CONFIG_EMBED_DRIVER = null;
private static final String DEFAULT_DATABASE_CONFIG_EMBED_URL = null; private static final String DEFAULT_DATABASE_CONFIG_EMBED_URL = null;
@ -1311,6 +1319,30 @@ public class SettingsService {
setString(KEY_SMTP_FROM, smtpFrom); setString(KEY_SMTP_FROM, smtpFrom);
} }
public boolean isCaptchaEnabled() {
return getBoolean(KEY_CAPTCHA_ENABLED, DEFAULT_CAPTCHA_ENABLED);
}
public void setCaptchaEnabled(boolean captchaEnabled) {
setBoolean(KEY_CAPTCHA_ENABLED, captchaEnabled);
}
public String getRecaptchaSiteKey() {
return getProperty(KEY_RECAPTCHA_SITE_KEY, DEFAULT_RECAPTCHA_SITE_KEY);
}
public void setRecaptchaSiteKey(String recaptchaSiteKey) {
setString(KEY_RECAPTCHA_SITE_KEY, recaptchaSiteKey);
}
public String getRecaptchaSecretKey() {
return getProperty(KEY_RECAPTCHA_SECRET_KEY, DEFAULT_RECAPTCHA_SECRET_KEY);
}
public void setRecaptchaSecretKey(String recaptchaSecretKey) {
setString(KEY_RECAPTCHA_SECRET_KEY, recaptchaSecretKey);
}
public DataSourceConfigType getDatabaseConfigType() { public DataSourceConfigType getDatabaseConfigType() {
String raw = getString(KEY_DATABASE_CONFIG_TYPE, DEFAULT_DATABASE_CONFIG_TYPE.name()); String raw = getString(KEY_DATABASE_CONFIG_TYPE, DEFAULT_DATABASE_CONFIG_TYPE.name());
return DataSourceConfigType.valueOf(StringUtils.upperCase(raw)); return DataSourceConfigType.valueOf(StringUtils.upperCase(raw));

@ -338,6 +338,9 @@ advancedsettings.smtpEncryption.none=None
advancedsettings.smtpEncryption.starttls=STARTTLS advancedsettings.smtpEncryption.starttls=STARTTLS
advancedsettings.smtpEncryption.ssl=SSL/TLS advancedsettings.smtpEncryption.ssl=SSL/TLS
advancedsettings.smtpFrom=E-mail sender advancedsettings.smtpFrom=E-mail sender
advancedsettings.enableCaptcha=Require CAPTCHA for account recovery
advancedsettings.recaptchaSiteKey=reCAPTCHA site key
advancedsettings.recaptchaSecretKey=reCAPTCHA secret key
# personalSettings.jsp # personalSettings.jsp
personalsettings.title=Personal settings for {0} personalsettings.title=Personal settings for {0}
personalsettings.language=Language personalsettings.language=Language
@ -730,6 +733,12 @@ helppopup.smtpEncryption.title=SMTP Encryption
helppopup.smtpEncryption.text=<p>Encryption method used for connections to the SMTP server. Choose "None" for no encryption.</p> helppopup.smtpEncryption.text=<p>Encryption method used for connections to the SMTP server. Choose "None" for no encryption.</p>
helppopup.smtpFrom.title=From address helppopup.smtpFrom.title=From address
helppopup.smtpFrom.text=<p>The sender address for e-mails originating from the Airsonic server. Must be a valid e-mail address.</p> helppopup.smtpFrom.text=<p>The sender address for e-mails originating from the Airsonic server. Must be a valid e-mail address.</p>
helppopup.captcha.title=CAPTCHA
helppopup.captcha.text=<p>When enabled, users must solve a CAPTCHA to prove they are human when requesting a password reset.</p> <p>Requires registration with an external service; see the <a href="https://airsonic.github.io/docs/captcha/">documentation</a>.</p>
helppopup.recaptchaSiteKey.title=reCAPTCHA site key
helppopup.recaptchaSiteKey.text=<p>A site key obtained from the reCAPTCHA admin console.</p>
helppopup.recaptchaSecretKey.title=reCAPTCHA secret key
helppopup.recaptchaSecretKey.text=<p>A secret key obtained from the reCAPTCHA admin console. Left unchanged if blank.</p>
helppopup.scanMediaFolders.title=Media folders scanning rules helppopup.scanMediaFolders.title=Media folders scanning rules
helppopup.scanMediaFolders.text=<p>Note that subfolder names starting with a dot (.) or @eaDir, as well as Thumbs.db files, are ignored.</p> helppopup.scanMediaFolders.text=<p>Note that subfolder names starting with a dot (.) or @eaDir, as well as Thumbs.db files, are ignored.</p>
# wap/index.jsp # wap/index.jsp

@ -91,7 +91,34 @@
<c:import url="helpToolTip.jsp"><c:param name="topic" value="smtpCredentials"/></c:import> <c:import url="helpToolTip.jsp"><c:param name="topic" value="smtpCredentials"/></c:import>
</td> </td>
</tr> </tr>
</table>
<table class="indent">
<tr>
<td colspan="2">
<form:checkbox path="captchaEnabled" id="enablecaptcha" cssclass="checkbox"/>
<label for="enablecaptcha">
<fmt:message key="advancedsettings.enableCaptcha"/>
</label>
<c:import url="helpToolTip.jsp"><c:param name="topic" value="captcha"/></c:import>
</td>
</tr>
<tr>
<td><fmt:message key="advancedsettings.recaptchaSiteKey"/></td>
<td>
<form:input path="recaptchaSiteKey" size="50"/>
<c:import url="helpToolTip.jsp"><c:param name="topic" value="recaptchaSiteKey"/></c:import>
</td>
</tr>
<tr>
<td><fmt:message key="advancedsettings.recaptchaSecretKey"/></td>
<td>
<form:input path="recaptchaSecretKey" size="50"/>
<c:import url="helpToolTip.jsp"><c:param name="topic" value="recaptchaSecretKey"/></c:import>
</td>
</tr>
</table> </table>
<table class="indent"><tr><td> <table class="indent"><tr><td>
@ -152,4 +179,4 @@
</script> </script>
</c:if> </c:if>
</body></html> </body></html>

@ -21,9 +21,10 @@
<input name="submit" type="submit" value="<fmt:message key="recover.send"/>"> <input name="submit" type="submit" value="<fmt:message key="recover.send"/>">
</c:if> </c:if>
<c:if test="${not empty model.captcha}"> <c:if test="${not empty model.recaptchaSiteKey and empty model.sentTo}">
<p style="padding-top: 1em"> <p style="padding-top: 1em">
<c:out value="${model.captcha}" escapeXml="false"/> <script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey="${model.recaptchaSiteKey}"></div>
</p> </p>
</c:if> </c:if>

@ -1,6 +0,0 @@
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>net.tanesha.recaptcha4j</groupId>
<artifactId>recaptcha4j</artifactId>
<version>0.0.8</version>
</project>
Loading…
Cancel
Save