mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
recover password (wip)
This commit is contained in:
@@ -44,4 +44,19 @@ public class UserDAO extends GenericDAO<User> {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public User findByEmail(String email) {
|
||||||
|
CriteriaQuery<User> query = builder.createQuery(getType());
|
||||||
|
Root<User> root = query.from(getType());
|
||||||
|
query.where(builder.equal(root.get(User_.email), email));
|
||||||
|
TypedQuery<User> q = em.createQuery(query);
|
||||||
|
|
||||||
|
User user = null;
|
||||||
|
try {
|
||||||
|
user = q.getSingleResult();
|
||||||
|
} catch (NoResultException e) {
|
||||||
|
user = null;
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ public class User extends AbstractModel {
|
|||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
private Date lastLogin;
|
private Date lastLogin;
|
||||||
|
|
||||||
|
@Column(length = 40)
|
||||||
|
private String recoverPasswordToken;
|
||||||
|
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date recoverPasswordTokenDate;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "user", cascade = CascadeType.PERSIST)
|
@OneToMany(mappedBy = "user", cascade = CascadeType.PERSIST)
|
||||||
private Set<UserRole> roles = Sets.newHashSet();
|
private Set<UserRole> roles = Sets.newHashSet();
|
||||||
|
|
||||||
@@ -110,4 +116,20 @@ public class User extends AbstractModel {
|
|||||||
this.apiKey = apiKey;
|
this.apiKey = apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRecoverPasswordToken() {
|
||||||
|
return recoverPasswordToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecoverPasswordToken(String recoverPasswordToken) {
|
||||||
|
this.recoverPasswordToken = recoverPasswordToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getRecoverPasswordTokenDate() {
|
||||||
|
return recoverPasswordTokenDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecoverPasswordTokenDate(Date recoverPasswordTokenDate) {
|
||||||
|
this.recoverPasswordTokenDate = recoverPasswordTokenDate;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ import com.google.api.client.util.Lists;
|
|||||||
|
|
||||||
@Stateless
|
@Stateless
|
||||||
public class FeedSubscriptionService {
|
public class FeedSubscriptionService {
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
@ApplicationException
|
@ApplicationException
|
||||||
public class FeedSubscriptionException extends RuntimeException {
|
public static class FeedSubscriptionException extends RuntimeException {
|
||||||
public FeedSubscriptionException(String msg) {
|
public FeedSubscriptionException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
@@ -51,10 +53,10 @@ public class FeedSubscriptionService {
|
|||||||
final String pubUrl = applicationSettingsService.get().getPublicUrl();
|
final String pubUrl = applicationSettingsService.get().getPublicUrl();
|
||||||
if (pubUrl == null) {
|
if (pubUrl == null) {
|
||||||
throw new FeedSubscriptionException(
|
throw new FeedSubscriptionException(
|
||||||
"Public URL of this CommaFeed is unset");
|
"Public URL of this CommaFeed is unset");
|
||||||
}
|
}
|
||||||
if (url.startsWith(pubUrl)) {
|
if (url.startsWith(pubUrl)) {
|
||||||
throw new RuntimeException(
|
throw new FeedSubscriptionException(
|
||||||
"Could not subscribe to a feed from this CommaFeed instance");
|
"Could not subscribe to a feed from this CommaFeed instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.commafeed.backend.services;
|
package com.commafeed.backend.services;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.mail.Authenticator;
|
||||||
import javax.mail.Message;
|
import javax.mail.Message;
|
||||||
import javax.mail.PasswordAuthentication;
|
import javax.mail.PasswordAuthentication;
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
@@ -10,35 +12,47 @@ import javax.mail.Transport;
|
|||||||
import javax.mail.internet.InternetAddress;
|
import javax.mail.internet.InternetAddress;
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.commafeed.backend.model.ApplicationSettings;
|
import com.commafeed.backend.model.ApplicationSettings;
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.User;
|
||||||
|
|
||||||
public class MailService {
|
@SuppressWarnings("serial")
|
||||||
|
public class MailService implements Serializable {
|
||||||
|
|
||||||
|
private static Logger log = LoggerFactory.getLogger(MailService.class);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ApplicationSettingsService applicationSettingsService;
|
ApplicationSettingsService applicationSettingsService;
|
||||||
|
|
||||||
public void sendMail(User user, String subject, String content) throws Exception {
|
public void sendMail(User user, String subject, String content)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
ApplicationSettings settings = applicationSettingsService.get();
|
ApplicationSettings settings = applicationSettingsService.get();
|
||||||
|
|
||||||
final String username = settings.getSmtpUserName();
|
final String username = settings.getSmtpUserName();
|
||||||
final String password = settings.getSmtpPassword();
|
final String password = settings.getSmtpPassword();
|
||||||
|
|
||||||
|
log.info(username);
|
||||||
|
log.info(password);
|
||||||
|
log.info("" + settings.isSmtpTls());
|
||||||
|
log.info(settings.getSmtpHost());
|
||||||
|
log.info("" + settings.getSmtpPort());
|
||||||
|
|
||||||
String dest = user.getEmail();
|
String dest = user.getEmail();
|
||||||
|
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.put("mail.smtp.auth", "true");
|
props.put("mail.smtp.auth", "true");
|
||||||
props.put("mail.smtp.starttls.enable", settings.isSmtpTls());
|
props.put("mail.smtp.starttls.enable", "" + settings.isSmtpTls());
|
||||||
props.put("mail.smtp.host", settings.getSmtpHost());
|
props.put("mail.smtp.host", settings.getSmtpHost());
|
||||||
props.put("mail.smtp.port", settings.getSmtpPort());
|
props.put("mail.smtp.port", "" + settings.getSmtpPort());
|
||||||
|
|
||||||
Session session = Session.getInstance(props,
|
Session session = Session.getInstance(props, new Authenticator() {
|
||||||
new javax.mail.Authenticator() {
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
protected PasswordAuthentication getPasswordAuthentication() {
|
return new PasswordAuthentication(username, password);
|
||||||
return new PasswordAuthentication(username, password);
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
Message message = new MimeMessage(session);
|
Message message = new MimeMessage(session);
|
||||||
message.setFrom(new InternetAddress(username, "CommaFeed"));
|
message.setFrom(new InternetAddress(username, "CommaFeed"));
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ package com.commafeed.backend.services;
|
|||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.ejb.Stateless;
|
import javax.ejb.Stateless;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||||
@@ -94,4 +97,10 @@ public class UserService {
|
|||||||
userRoleDAO.delete(userRoleDAO.findAll(user));
|
userRoleDAO.delete(userRoleDAO.findAll(user));
|
||||||
userDAO.delete(user);
|
userDAO.delete(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String generateApiKey(User user) {
|
||||||
|
byte[] key = encryptionService.getEncryptedPassword(UUID.randomUUID()
|
||||||
|
.toString(), user.getSalt());
|
||||||
|
return DigestUtils.sha1Hex(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ import com.commafeed.frontend.pages.GoogleImportRedirectPage;
|
|||||||
import com.commafeed.frontend.pages.HomePage;
|
import com.commafeed.frontend.pages.HomePage;
|
||||||
import com.commafeed.frontend.pages.LogoutPage;
|
import com.commafeed.frontend.pages.LogoutPage;
|
||||||
import com.commafeed.frontend.pages.NextUnreadRedirectPage;
|
import com.commafeed.frontend.pages.NextUnreadRedirectPage;
|
||||||
|
import com.commafeed.frontend.pages.PasswordRecoveryCallbackPage;
|
||||||
|
import com.commafeed.frontend.pages.PasswordRecoveryPage;
|
||||||
import com.commafeed.frontend.pages.WelcomePage;
|
import com.commafeed.frontend.pages.WelcomePage;
|
||||||
import com.commafeed.frontend.utils.exception.DisplayExceptionPage;
|
import com.commafeed.frontend.utils.exception.DisplayExceptionPage;
|
||||||
|
|
||||||
@@ -66,8 +68,13 @@ public class CommaFeedApplication extends AuthenticatedWebApplication {
|
|||||||
|
|
||||||
mountPage("welcome", WelcomePage.class);
|
mountPage("welcome", WelcomePage.class);
|
||||||
mountPage("demo", DemoLoginPage.class);
|
mountPage("demo", DemoLoginPage.class);
|
||||||
|
|
||||||
|
mountPage("recover", PasswordRecoveryPage.class);
|
||||||
|
mountPage("recover2", PasswordRecoveryCallbackPage.class);
|
||||||
|
|
||||||
mountPage("logout", LogoutPage.class);
|
mountPage("logout", LogoutPage.class);
|
||||||
mountPage("error", DisplayExceptionPage.class);
|
mountPage("error", DisplayExceptionPage.class);
|
||||||
|
|
||||||
mountPage("google/import/redirect", GoogleImportRedirectPage.class);
|
mountPage("google/import/redirect", GoogleImportRedirectPage.class);
|
||||||
mountPage(GoogleImportCallbackPage.PAGE_PATH,
|
mountPage(GoogleImportCallbackPage.PAGE_PATH,
|
||||||
GoogleImportCallbackPage.class);
|
GoogleImportCallbackPage.class);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.commafeed.backend.model.ApplicationSettings;
|
|||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.User;
|
||||||
import com.commafeed.backend.model.UserSettings;
|
import com.commafeed.backend.model.UserSettings;
|
||||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||||
|
import com.commafeed.backend.services.MailService;
|
||||||
import com.commafeed.frontend.CommaFeedSession;
|
import com.commafeed.frontend.CommaFeedSession;
|
||||||
import com.commafeed.frontend.utils.WicketUtils;
|
import com.commafeed.frontend.utils.WicketUtils;
|
||||||
import com.google.api.client.util.Maps;
|
import com.google.api.client.util.Maps;
|
||||||
@@ -61,6 +62,9 @@ public abstract class BasePage extends WebPage {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected UserRoleDAO userRoleDAO;
|
protected UserRoleDAO userRoleDAO;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MailService mailService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ApplicationSettingsService applicationSettingsService;
|
ApplicationSettingsService applicationSettingsService;
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<html xmlns:wicket="http://wicket.apache.org">
|
||||||
|
<body>
|
||||||
|
<wicket:extend>
|
||||||
|
<div class="container">
|
||||||
|
<div class="text-center">
|
||||||
|
<img src="images/logo_2.png" />
|
||||||
|
<div wicket:id="feedback"></div>
|
||||||
|
<form wicket:id="form">
|
||||||
|
Password:
|
||||||
|
<input type="password" wicket:id="password" />
|
||||||
|
<br />
|
||||||
|
Password:
|
||||||
|
<input type="password" wicket:id="confirm" />
|
||||||
|
<br />
|
||||||
|
<input type="submit" class="btn btn-primary" value="Submit" />
|
||||||
|
<input type="button" class="btn" wicket:id="cancel" value="Home page" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</wicket:extend>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.commafeed.frontend.pages;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import org.apache.wicket.markup.html.form.Form;
|
||||||
|
import org.apache.wicket.markup.html.form.PasswordTextField;
|
||||||
|
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
||||||
|
import org.apache.wicket.model.IModel;
|
||||||
|
import org.apache.wicket.model.Model;
|
||||||
|
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||||
|
import org.apache.wicket.validation.validator.StringValidator;
|
||||||
|
|
||||||
|
import com.commafeed.backend.model.User;
|
||||||
|
import com.commafeed.backend.services.PasswordEncryptionService;
|
||||||
|
import com.commafeed.backend.services.UserService;
|
||||||
|
import com.commafeed.frontend.pages.components.BootstrapFeedbackPanel;
|
||||||
|
import com.commafeed.frontend.utils.exception.DisplayException;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class PasswordRecoveryCallbackPage extends BasePage {
|
||||||
|
|
||||||
|
public static final String PARAM_EMAIL = "email";
|
||||||
|
public static final String PARAM_TOKEN = "token";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PasswordEncryptionService encryptionService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
UserService userService;
|
||||||
|
|
||||||
|
public PasswordRecoveryCallbackPage(PageParameters params) {
|
||||||
|
String email = params.get(PARAM_EMAIL).toString();
|
||||||
|
String token = params.get(PARAM_TOKEN).toString();
|
||||||
|
|
||||||
|
final User user = userDAO.findByEmail(email);
|
||||||
|
if (user == null) {
|
||||||
|
throw new DisplayException("email not found");
|
||||||
|
}
|
||||||
|
if (user.getRecoverPasswordToken() == null
|
||||||
|
|| !user.getRecoverPasswordToken().equals(token)) {
|
||||||
|
throw new DisplayException("invalid token");
|
||||||
|
}
|
||||||
|
if (user.getRecoverPasswordTokenDate().before(
|
||||||
|
DateUtils.addDays(Calendar.getInstance().getTime(), -2))) {
|
||||||
|
throw new DisplayException("token expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
final IModel<String> password = new Model<String>();
|
||||||
|
final IModel<String> confirm = new Model<String>();
|
||||||
|
add(new BootstrapFeedbackPanel("feedback"));
|
||||||
|
Form<Void> form = new Form<Void>("form") {
|
||||||
|
@Override
|
||||||
|
protected void onSubmit() {
|
||||||
|
String passwd = password.getObject();
|
||||||
|
if (StringUtils.equals(passwd, confirm.getObject())) {
|
||||||
|
byte[] password = encryptionService.getEncryptedPassword(
|
||||||
|
passwd, user.getSalt());
|
||||||
|
user.setPassword(password);
|
||||||
|
user.setApiKey(userService.generateApiKey(user));
|
||||||
|
userDAO.update(user);
|
||||||
|
info("Password saved.");
|
||||||
|
} else {
|
||||||
|
error("Password do not match");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add(form);
|
||||||
|
form.add(new PasswordTextField("password", password).setResetPassword(
|
||||||
|
true).add(StringValidator.minimumLength(6)));
|
||||||
|
form.add(new PasswordTextField("confirm", confirm).setResetPassword(
|
||||||
|
true).add(StringValidator.minimumLength(6)));
|
||||||
|
|
||||||
|
form.add(new BookmarkablePageLink<Void>("cancel", HomePage.class));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<html xmlns:wicket="http://wicket.apache.org">
|
||||||
|
<body>
|
||||||
|
<wicket:extend>
|
||||||
|
<div class="container">
|
||||||
|
<div class="text-center">
|
||||||
|
<img src="images/logo_2.png" />
|
||||||
|
<div wicket:id="feedback"></div>
|
||||||
|
<form wicket:id="form">
|
||||||
|
Email:
|
||||||
|
<input type="email" wicket:id="email" />
|
||||||
|
<br />
|
||||||
|
<input type="submit" class="btn btn-primary" value="Submit" />
|
||||||
|
<input type="button" class="btn" wicket:id="cancel" value="Cancel" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</wicket:extend>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.commafeed.frontend.pages;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.apache.wicket.extensions.validation.validator.RfcCompliantEmailAddressValidator;
|
||||||
|
import org.apache.wicket.markup.html.form.Form;
|
||||||
|
import org.apache.wicket.markup.html.form.RequiredTextField;
|
||||||
|
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
||||||
|
import org.apache.wicket.model.IModel;
|
||||||
|
import org.apache.wicket.model.Model;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.commafeed.backend.model.User;
|
||||||
|
import com.commafeed.frontend.pages.components.BootstrapFeedbackPanel;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class PasswordRecoveryPage extends BasePage {
|
||||||
|
|
||||||
|
private static Logger log = LoggerFactory
|
||||||
|
.getLogger(PasswordRecoveryPage.class);
|
||||||
|
|
||||||
|
public PasswordRecoveryPage() {
|
||||||
|
|
||||||
|
IModel<String> email = new Model<String>();
|
||||||
|
add(new BootstrapFeedbackPanel("feedback"));
|
||||||
|
Form<String> form = new Form<String>("form", email) {
|
||||||
|
@Override
|
||||||
|
protected void onSubmit() {
|
||||||
|
super.onSubmit();
|
||||||
|
User user = userDAO.findByEmail(getModelObject());
|
||||||
|
if (user == null) {
|
||||||
|
error("Email not found.");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
user.setRecoverPasswordToken(DigestUtils.sha1Hex(UUID
|
||||||
|
.randomUUID().toString()));
|
||||||
|
user.setRecoverPasswordTokenDate(Calendar.getInstance()
|
||||||
|
.getTime());
|
||||||
|
userDAO.update(user);
|
||||||
|
mailService.sendMail(user,
|
||||||
|
"CommaFeed - Password recovery",
|
||||||
|
buildEmailContent(user));
|
||||||
|
info("Email sent.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
error("Cannot send email, please contact the staff.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
add(form);
|
||||||
|
|
||||||
|
form.add(new RequiredTextField<String>("email", email) {
|
||||||
|
@Override
|
||||||
|
protected String getInputType() {
|
||||||
|
return "email";
|
||||||
|
}
|
||||||
|
}.add(RfcCompliantEmailAddressValidator.getInstance()));
|
||||||
|
|
||||||
|
form.add(new BookmarkablePageLink<Void>("cancel", HomePage.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildEmailContent(User user) {
|
||||||
|
return "cc";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<input type="submit" class="btn btn-primary" value="Log in" />
|
<input type="submit" class="btn btn-primary" value="Log in" />
|
||||||
|
<a wicket:id="recover" class="pull-right">Forgot password?</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</wicket:panel>
|
</wicket:panel>
|
||||||
|
|||||||
@@ -1,15 +1,36 @@
|
|||||||
package com.commafeed.frontend.pages.components;
|
package com.commafeed.frontend.pages.components;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.wicket.authroles.authentication.panel.SignInPanel;
|
import org.apache.wicket.authroles.authentication.panel.SignInPanel;
|
||||||
import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
|
import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
|
||||||
|
import org.apache.wicket.markup.html.form.Form;
|
||||||
|
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
||||||
|
|
||||||
|
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||||
|
import com.commafeed.frontend.pages.PasswordRecoveryPage;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class LoginPanel extends SignInPanel {
|
public class LoginPanel extends SignInPanel {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ApplicationSettingsService applicationSettingsService;
|
||||||
|
|
||||||
public LoginPanel(String id) {
|
public LoginPanel(String id) {
|
||||||
super(id);
|
super(id);
|
||||||
replace(new BootstrapFeedbackPanel("feedback",
|
replace(new BootstrapFeedbackPanel("feedback",
|
||||||
new ContainerFeedbackMessageFilter(this)));
|
new ContainerFeedbackMessageFilter(this)));
|
||||||
|
Form<?> form = (Form<?>) get("signInForm");
|
||||||
|
form.add(new BookmarkablePageLink<Void>("recover",
|
||||||
|
PasswordRecoveryPage.class){
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
String smtpHost = applicationSettingsService.get().getSmtpHost();
|
||||||
|
setVisibilityAllowed(StringUtils.isNotBlank(smtpHost));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,12 +226,13 @@ public class FeedREST extends AbstractResourceREST {
|
|||||||
FeedInfo info = (FeedInfo) fetchFeed(url).getEntity();
|
FeedInfo info = (FeedInfo) fetchFeed(url).getEntity();
|
||||||
try {
|
try {
|
||||||
feedSubscriptionService.subscribe(getUser(), info.getUrl(),
|
feedSubscriptionService.subscribe(getUser(), info.getUrl(),
|
||||||
req.getTitle(), category);
|
req.getTitle(), category);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.info("Failed to subscribe to URL {}: {}", url, e.getMessage());
|
log.info("Failed to subscribe to URL {}: {}", url, e.getMessage());
|
||||||
return Response.status(Status.SERVICE_UNAVAILABLE).entity(
|
return Response
|
||||||
"Failed to subscribe to URL " + url + ": " + e.getMessage()
|
.status(Status.SERVICE_UNAVAILABLE)
|
||||||
).build();
|
.entity("Failed to subscribe to URL " + url + ": "
|
||||||
|
+ e.getMessage()).build();
|
||||||
}
|
}
|
||||||
return Response.ok(Status.OK).build();
|
return Response.ok(Status.OK).build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
package com.commafeed.frontend.rest.resources;
|
package com.commafeed.frontend.rest.resources;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
import com.commafeed.backend.StartupBean;
|
import com.commafeed.backend.StartupBean;
|
||||||
@@ -120,10 +117,10 @@ public class UserREST extends AbstractResourceREST {
|
|||||||
byte[] password = encryptionService.getEncryptedPassword(
|
byte[] password = encryptionService.getEncryptedPassword(
|
||||||
request.getPassword(), user.getSalt());
|
request.getPassword(), user.getSalt());
|
||||||
user.setPassword(password);
|
user.setPassword(password);
|
||||||
user.setApiKey(generateKey(user));
|
user.setApiKey(userService.generateApiKey(user));
|
||||||
}
|
}
|
||||||
if (request.isNewApiKey()) {
|
if (request.isNewApiKey()) {
|
||||||
user.setApiKey(generateKey(user));
|
user.setApiKey(userService.generateApiKey(user));
|
||||||
}
|
}
|
||||||
userDAO.update(user);
|
userDAO.update(user);
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
@@ -140,10 +137,4 @@ public class UserREST extends AbstractResourceREST {
|
|||||||
userService.unregister(getUser());
|
userService.unregister(getUser());
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateKey(User user) {
|
|
||||||
byte[] key = encryptionService.getEncryptedPassword(UUID.randomUUID()
|
|
||||||
.toString(), user.getSalt());
|
|
||||||
return DigestUtils.sha1Hex(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,66 +10,107 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<form name="settingsForm" class="form-horizontal" ng-submit="save()">
|
<form name="settingsForm" class="form-horizontal" ng-submit="save()">
|
||||||
<div class="control-group">
|
<div class="row-fluid">
|
||||||
<label class="control-label" for="publicUrl">Public URL</label>
|
<div class="span6">
|
||||||
<div class="controls">
|
<div class="control-group">
|
||||||
<input type="text" id="publicUrl" name="publicUrl"
|
<label class="control-label" for="publicUrl">Public URL</label>
|
||||||
ng-model="settings.publicUrl" />
|
<div class="controls">
|
||||||
|
<input type="text" id="publicUrl" name="publicUrl"
|
||||||
|
ng-model="settings.publicUrl" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="allowRegistrations">Allow
|
||||||
|
registrations</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="checkbox" id="allowRegistrations"
|
||||||
|
name="allowRegistrations" ng-model="settings.allowRegistrations" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="feedbackButton">Feedback
|
||||||
|
button</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="checkbox" id="feedbackButton" name="feedbackButton"
|
||||||
|
ng-model="settings.feedbackButton" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="googleClientId">Google
|
||||||
|
client ID</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="googleClientId"
|
||||||
|
ng-model="settings.googleClientId" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="googleClientSecret">Google
|
||||||
|
client secret</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="googleClientSecret"
|
||||||
|
ng-model="settings.googleClientSecret" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="googleAnalyticsTrackingCode">Google
|
||||||
|
Analytics tracking code</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="googleAnalyticsTrackingCode"
|
||||||
|
ng-model="settings.googleAnalyticsTrackingCode" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="googleClientSecret">Background
|
||||||
|
threads</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="number" name="backgroundThreads"
|
||||||
|
ng-model="settings.backgroundThreads" />
|
||||||
|
<span class="help-inline">Requires restart</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="announcement">Announcement</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="announcement"
|
||||||
|
ng-model="settings.announcement" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="span6">
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label class="control-label" for="allowRegistrations">Allow
|
<label class="control-label" for="announcement">SMTP Host</label>
|
||||||
registrations</label>
|
<div class="controls">
|
||||||
<div class="controls">
|
<input type="text" name="smtpHost" ng-model="settings.smtpHost" />
|
||||||
<input type="checkbox" id="allowRegistrations"
|
</div>
|
||||||
name="allowRegistrations" ng-model="settings.allowRegistrations" />
|
</div>
|
||||||
</div>
|
<div class="control-group">
|
||||||
</div>
|
<label class="control-label" for="announcement">SMTP Port</label>
|
||||||
<div class="control-group">
|
<div class="controls">
|
||||||
<label class="control-label" for="feedbackButton">Feedback button</label>
|
<input type="text" name="smtpPort" ng-model="settings.smtpPort" />
|
||||||
<div class="controls">
|
</div>
|
||||||
<input type="checkbox" id="feedbackButton"
|
</div>
|
||||||
name="feedbackButton" ng-model="settings.feedbackButton" />
|
<div class="control-group">
|
||||||
</div>
|
<label class="control-label" for="smtpTls">SMTP TLS </label>
|
||||||
</div>
|
<div class="controls">
|
||||||
<div class="control-group">
|
<input type="checkbox" name="smtpTls" ng-model="settings.smtpTls" />
|
||||||
<label class="control-label" for="googleClientId">Google
|
</div>
|
||||||
client ID</label>
|
</div>
|
||||||
<div class="controls">
|
<div class="control-group">
|
||||||
<input type="text" name="googleClientId"
|
<label class="control-label" for="smtpUserName">SMTP
|
||||||
ng-model="settings.googleClientId" />
|
Username</label>
|
||||||
</div>
|
<div class="controls">
|
||||||
</div>
|
<input type="text" name="smtpUserName"
|
||||||
<div class="control-group">
|
ng-model="settings.smtpUserName" />
|
||||||
<label class="control-label" for="googleClientSecret">Google
|
</div>
|
||||||
client secret</label>
|
</div>
|
||||||
<div class="controls">
|
<div class="control-group">
|
||||||
<input type="text" name="googleClientSecret"
|
<label class="control-label" for="smtpPassword">SMTP
|
||||||
ng-model="settings.googleClientSecret" />
|
Password</label>
|
||||||
</div>
|
<div class="controls">
|
||||||
</div>
|
<input type="password" name="smtpPassword"
|
||||||
<div class="control-group">
|
ng-model="settings.smtpPassword" />
|
||||||
<label class="control-label" for="googleAnalyticsTrackingCode">Google
|
</div>
|
||||||
Analytics tracking code</label>
|
</div>
|
||||||
<div class="controls">
|
|
||||||
<input type="text" name="googleAnalyticsTrackingCode"
|
|
||||||
ng-model="settings.googleAnalyticsTrackingCode" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="googleClientSecret">Background
|
|
||||||
threads</label>
|
|
||||||
<div class="controls">
|
|
||||||
<input type="number" name="backgroundThreads"
|
|
||||||
ng-model="settings.backgroundThreads" />
|
|
||||||
<span class="help-inline">Requires restart</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="announcement">Announcement</label>
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" name="announcement"
|
|
||||||
ng-model="settings.announcement" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
|
|||||||
Reference in New Issue
Block a user