Skip to content

Commit f2feff7

Browse files
authored
Merge pull request #110 from maelgangloff/feat/reset-password
feat(auth): password reset
2 parents c04eef3 + 72f3442 commit f2feff7

File tree

13 files changed

+20194
-8655
lines changed

13 files changed

+20194
-8655
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!--
2+
GMCServer, lightweight service to log, analyze and proxy Geiger counter data.
3+
Copyright (C) 2020 Vincent Hyvert
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Affero General Public as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Affero General Public for more details.
14+
15+
You should have received a copy of the GNU Affero General Public
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
-->
18+
19+
<mjml>
20+
<mj-include path="./fragments/head.mjml"/>
21+
<mj-body>
22+
<mj-include path="./fragments/header.mjml"/>
23+
<mj-section background-color="#424242" border-radius="4px">
24+
<mj-column>
25+
<mj-text>
26+
<h2>
27+
Password reset
28+
</h2>
29+
Click on the following link to reset the password of your account.<br/>
30+
</mj-text>
31+
<mj-button
32+
href="https://{{instance/host}}/password-reset/confirm?token={{token}}"
33+
>
34+
Reset my password
35+
</mj-button>
36+
</mj-column>
37+
</mj-section>
38+
<mj-include path="./fragments/footer.mjml"/>
39+
</mj-body>
40+
</mjml>

gmcserver-email/pnpm-lock.yaml

Lines changed: 1043 additions & 695 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gmcserver-server/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<gmc.config.path>./config.properties</gmc.config.path>
3838
<gmc.vertx.config.path>./vertx.json</gmc.vertx.config.path>
3939
<gmc.vertx.mail.config.path>./mail.json</gmc.vertx.mail.config.path>
40-
<gmc.vertx.mail.templates.path>./gmcserver-email/out/</gmc.vertx.mail.templates.path>
40+
<gmc.vertx.mail.templates.path>../gmcserver-email/out/</gmc.vertx.mail.templates.path>
4141

4242
<vertx.version>4.3.8</vertx.version>
4343
</properties>
@@ -55,6 +55,11 @@
5555
<artifactId>vertx-web</artifactId>
5656
<version>${vertx.version}</version>
5757
</dependency>
58+
<dependency>
59+
<groupId>io.netty</groupId>
60+
<artifactId>netty-codec</artifactId>
61+
<version>4.1.87.Final</version>
62+
</dependency>
5863
<dependency>
5964
<groupId>io.vertx</groupId>
6065
<artifactId>vertx-web-client</artifactId>

gmcserver-server/src/main/java/me/vinceh121/gmcserver/auth/InternalAuthenticator.java

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818
package me.vinceh121.gmcserver.auth;
1919

2020
import com.mongodb.client.model.Filters;
21-
21+
import com.mongodb.client.model.Updates;
2222
import io.vertx.core.Future;
2323
import me.vinceh121.gmcserver.GMCServer;
2424
import me.vinceh121.gmcserver.entities.User;
2525
import me.vinceh121.gmcserver.exceptions.AuthenticationException;
2626
import me.vinceh121.gmcserver.exceptions.EntityNotFoundException;
2727
import me.vinceh121.gmcserver.managers.UserManager.CreateUserAction;
28+
import me.vinceh121.gmcserver.managers.email.Email;
29+
30+
import java.util.UUID;
2831

2932
public class InternalAuthenticator extends AbstractAuthenticator {
3033

@@ -33,17 +36,17 @@ public InternalAuthenticator(final GMCServer srv) {
3336
}
3437

3538
/**
36-
* @exception EntityNotFoundException if the user what not found
37-
* @exception IllegalStateException if the user's account is disabled
38-
* @exception AuthenticationException if the password failed to validate
39+
* @throws EntityNotFoundException if the user what not found
40+
* @throws IllegalStateException if the user's account is disabled
41+
* @throws AuthenticationException if the password failed to validate
3942
*/
4043
@Override
4144
public Future<User> login(final String username, final String password) {
4245
return Future.future(promise -> {
4346
final User user = this.srv.getDatabaseManager()
44-
.getCollection(User.class)
45-
.find(Filters.or(Filters.eq("username", username), Filters.eq("email", username)))
46-
.first();
47+
.getCollection(User.class)
48+
.find(Filters.or(Filters.eq("username", username), Filters.eq("email", username)))
49+
.first();
4750

4851
if (user == null) {
4952
promise.fail(new EntityNotFoundException("User not found"));
@@ -70,11 +73,37 @@ public Future<User> login(final String username, final String password) {
7073
public Future<User> register(final String username, final String email, final String password) {
7174
return Future.future(promise -> {
7275
final CreateUserAction action = this.srv.getUserManager()
73-
.createUser()
74-
.setUsername(username)
75-
.setPassword(password)
76-
.setEmail(email);
76+
.createUser()
77+
.setUsername(username)
78+
.setPassword(password)
79+
.setEmail(email);
7780
action.execute().onSuccess(promise::complete).onFailure(promise::fail);
7881
});
7982
}
83+
84+
public Future<Void> sendPasswordResetLink(final User user) {
85+
return Future.future(promise -> {
86+
if (user == null) {
87+
promise.fail(new EntityNotFoundException("User not found"));
88+
return;
89+
}
90+
91+
final UUID id = UUID.randomUUID();
92+
93+
this.srv.getDatabaseManager().getCollection(User.class)
94+
.updateOne(Filters.eq(user.getId()),
95+
Updates.set("passwordResetToken", id.toString())
96+
);
97+
98+
final Email email = new Email();
99+
email.setTo(user);
100+
email.setTemplate("password-reset");
101+
email.setSubject("Password reset");
102+
email.getContext().put("token", id.toString());
103+
104+
this.srv.getEmailManager().sendEmail(email)
105+
.onSuccess(promise::complete)
106+
.onFailure(promise::fail);
107+
});
108+
}
80109
}

gmcserver-server/src/main/java/me/vinceh121/gmcserver/entities/User.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@
1717
*/
1818
package me.vinceh121.gmcserver.entities;
1919

20-
import org.bson.codecs.pojo.annotations.BsonIgnore;
21-
2220
import com.fasterxml.jackson.annotation.JsonIgnore;
23-
2421
import io.vertx.core.json.JsonObject;
2522
import me.vinceh121.gmcserver.mfa.MFAKey;
23+
import org.bson.codecs.pojo.annotations.BsonIgnore;
2624
import xyz.bowser65.tokenize.IAccount;
2725

2826
/**
@@ -40,6 +38,7 @@ public class User extends AbstractEntity implements IAccount {
4038
private long gmcId;
4139
private boolean admin, mfa, alertEmails;
4240
private MFAKey mfaKey;
41+
private String passwordResetToken;
4342

4443
public long getGmcId() {
4544
return this.gmcId;
@@ -151,4 +150,11 @@ public String toString() {
151150
return this.getUsername() + " (" + this.getId().toString() + ")";
152151
}
153152

153+
public void setPasswordResetToken(String passwordResetToken) {
154+
this.passwordResetToken = passwordResetToken;
155+
}
156+
157+
public String getPasswordResetToken() {
158+
return passwordResetToken;
159+
}
154160
}

gmcserver-server/src/main/java/me/vinceh121/gmcserver/managers/email/EmailManager.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@
1717
*/
1818
package me.vinceh121.gmcserver.managers.email;
1919

20-
import java.io.IOException;
21-
import java.nio.file.Files;
22-
import java.nio.file.Paths;
23-
import java.util.regex.Matcher;
24-
import java.util.regex.Pattern;
25-
2620
import io.vertx.core.Future;
2721
import io.vertx.core.Promise;
2822
import io.vertx.core.json.JsonObject;
@@ -34,6 +28,12 @@
3428
import me.vinceh121.gmcserver.GMCServer;
3529
import me.vinceh121.gmcserver.managers.AbstractManager;
3630

31+
import java.io.IOException;
32+
import java.nio.file.Files;
33+
import java.nio.file.Paths;
34+
import java.util.regex.Matcher;
35+
import java.util.regex.Pattern;
36+
3737
public class EmailManager extends AbstractManager {
3838
public static final Pattern VAR_PATTERN = Pattern.compile("\\{\\{[a-zA-Z/-_]+\\}\\}");
3939
private final MailClient client;

0 commit comments

Comments
 (0)