notherbase-fs 4.1.3 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/controllers/user.js +111 -7
- package/models/send-mail.js +1 -14
- package/notherbase-fs.js +22 -4
- package/package.json +1 -1
- package/public/js/base.js +12 -0
- package/test/the-front/check/_preprocess/saved.js +1 -1
- package/test/the-front/index.ejs +17 -2
package/controllers/user.js
CHANGED
|
@@ -11,6 +11,8 @@ export default class User {
|
|
|
11
11
|
|
|
12
12
|
this.router.post("/logout", this.logout);
|
|
13
13
|
this.router.post("/changePassword", this.changePassword);
|
|
14
|
+
this.router.post("/sendOTP", this.sendOneTimePassword);
|
|
15
|
+
this.router.post("/changeEmail", this.changeEmail);
|
|
14
16
|
this.router.post("/register", this.register);
|
|
15
17
|
this.router.post("/login", this.login);
|
|
16
18
|
this.router.post("/deletePermanently", this.deletePermanently);
|
|
@@ -20,6 +22,7 @@ export default class User {
|
|
|
20
22
|
this.router.post("/downloadData", this.downloadData);
|
|
21
23
|
this.router.post("/deleteAlldata", this.deleteAlldata);
|
|
22
24
|
this.router.post("/importData", this.importData);
|
|
25
|
+
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
/**
|
|
@@ -28,7 +31,7 @@ export default class User {
|
|
|
28
31
|
* @param {Object} res An Express.js response.
|
|
29
32
|
*/
|
|
30
33
|
logout = async (req, res) => {
|
|
31
|
-
await req.session
|
|
34
|
+
await req.session?.destroy();
|
|
32
35
|
|
|
33
36
|
success(res, "Logged out.");
|
|
34
37
|
}
|
|
@@ -65,6 +68,86 @@ export default class User {
|
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
validatePassword = async (req, password, user) => {
|
|
72
|
+
if (password && user?.memory?.data?.otp) {
|
|
73
|
+
if (password == user.memory.data.otp.code) {
|
|
74
|
+
if (Date.now() < user.memory.data.otp.expires) {
|
|
75
|
+
user.memory.data.otp.expires = 0;
|
|
76
|
+
await user.commit();
|
|
77
|
+
return "Authenticated.";
|
|
78
|
+
}
|
|
79
|
+
else return "One-time password expired.";
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
let passResult = await bcrypt.compare(req.body.password, user.memory.data.password);
|
|
83
|
+
if (passResult) return "Authenticated.";
|
|
84
|
+
else return "Password doesn't match the username.";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else return "Password error.";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Change a user's email.
|
|
92
|
+
* @param {Object} req An Express.js request.
|
|
93
|
+
* @param {Object} res An Express.js response.
|
|
94
|
+
*/
|
|
95
|
+
changeEmail = async (req, res) => {
|
|
96
|
+
if (loginCheck(req, res)) {
|
|
97
|
+
let spirit = await req.db.Spirit.recallOne("user", null, { username: req.session.currentUser });
|
|
98
|
+
|
|
99
|
+
if (check(res, spirit, "User not found!") &&
|
|
100
|
+
check(res, req.body.email, "New email must be provided."))
|
|
101
|
+
{
|
|
102
|
+
let result = await this.validatePassword(req, req.body.password, spirit);
|
|
103
|
+
if (result == "Authenticated.") {
|
|
104
|
+
let other = await req.db.Spirit.recallOne("user", null, { email: req.body.email });
|
|
105
|
+
|
|
106
|
+
if (check(res, !other, "Email already in use!")) {
|
|
107
|
+
spirit.addBackup({
|
|
108
|
+
...spirit.memory.data,
|
|
109
|
+
email: req.body.email
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await spirit.commit();
|
|
113
|
+
|
|
114
|
+
success(res, "Email changed successfully!");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else fail(res, result);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Send a one-time password to the user's email.
|
|
124
|
+
* @param {Object} req An Express.js request.
|
|
125
|
+
* @param {Object} res An Express.js response.
|
|
126
|
+
*/
|
|
127
|
+
sendOneTimePassword = async (req, res) => {
|
|
128
|
+
if (loginCheck(req, res)) {
|
|
129
|
+
let spirit = await req.db.Spirit.recallOne("user", null, { username: req.session.currentUser });
|
|
130
|
+
|
|
131
|
+
if (check(res, spirit, "User not found!")) {
|
|
132
|
+
let otp = Math.floor(100000 + Math.random() * 900000);
|
|
133
|
+
spirit.memory.data.otp = {
|
|
134
|
+
code: otp,
|
|
135
|
+
expires: Date.now() + 1000 * 60 * 15
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
await spirit.commit();
|
|
139
|
+
|
|
140
|
+
await req.db.SendMail.send(spirit.memory.data.email, 'One Time Password for NotherBase',
|
|
141
|
+
`<h1>Your One-Time Password:<h1>
|
|
142
|
+
<h2>${otp}<h2>
|
|
143
|
+
<p>Visit <a href="https://www.notherbase.com/the-front/keeper">notherbase.com/the-front/keeper</a> to use your one-time password.</p>
|
|
144
|
+
<p>This one-time password expires in 15 minutes.<p>`);
|
|
145
|
+
|
|
146
|
+
success(res, "One-time password sent.");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
68
151
|
/**
|
|
69
152
|
* Register a new user account.
|
|
70
153
|
* @param {Object} req An Express.js request.
|
|
@@ -84,7 +167,13 @@ export default class User {
|
|
|
84
167
|
username: req.body.username,
|
|
85
168
|
password: hash,
|
|
86
169
|
authLevels: [ "Basic" ],
|
|
87
|
-
view: "compact"
|
|
170
|
+
view: "compact",
|
|
171
|
+
email: "",
|
|
172
|
+
otp: {
|
|
173
|
+
code: "",
|
|
174
|
+
expires: 0
|
|
175
|
+
},
|
|
176
|
+
sessions: []
|
|
88
177
|
});
|
|
89
178
|
|
|
90
179
|
success(res, "Registration successful!");
|
|
@@ -99,15 +188,30 @@ export default class User {
|
|
|
99
188
|
*/
|
|
100
189
|
login = async (req, res) => {
|
|
101
190
|
let spirit = await req.db.Spirit.recallOne("user", null, { username: req.body.username });
|
|
102
|
-
|
|
103
191
|
if (check(res, spirit, "User not found.")) {
|
|
104
|
-
|
|
192
|
+
spirit.memory.data = {
|
|
193
|
+
username: "",
|
|
194
|
+
password: "",
|
|
195
|
+
authLevels: [ "Basic" ],
|
|
196
|
+
view: "compact",
|
|
197
|
+
email: "",
|
|
198
|
+
otp: {
|
|
199
|
+
code: "",
|
|
200
|
+
expires: 0
|
|
201
|
+
},
|
|
202
|
+
sessions: {},
|
|
203
|
+
...spirit.memory.data
|
|
204
|
+
}
|
|
205
|
+
await spirit.commit();
|
|
105
206
|
|
|
106
|
-
|
|
207
|
+
let result = await this.validatePassword(req, req.body.password, spirit);
|
|
208
|
+
if (result === "Authenticated.") {
|
|
107
209
|
req.session.currentUser = req.body.username;
|
|
108
|
-
|
|
109
|
-
|
|
210
|
+
spirit.memory.data.sessions[req.session.id] = Date.now() + 1000 * 60 * 60 * 24 * 28; // 28 days
|
|
211
|
+
await spirit.commit();
|
|
212
|
+
success(res, "Login successful!", req.body.username);
|
|
110
213
|
}
|
|
214
|
+
else fail(res, result);
|
|
111
215
|
}
|
|
112
216
|
}
|
|
113
217
|
|
package/models/send-mail.js
CHANGED
|
@@ -7,19 +7,6 @@ const OAuth2 = google.auth.OAuth2;
|
|
|
7
7
|
const OAuth2Client = new OAuth2(process.env.CLIENTID, process.env.CLIENTSECRET);
|
|
8
8
|
OAuth2Client.setCredentials({ refresh_token: process.env.CLIENTREFRESH });
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Sends an email with a password reset code. WIP
|
|
13
|
-
* @param {String} toEmail Email address to send to.
|
|
14
|
-
* @param {Number} resetToken Token to reset by.
|
|
15
|
-
*/
|
|
16
|
-
const passwordReset = async (toEmail, resetToken) => {
|
|
17
|
-
return await send(toEmail, 'Password Reset for NotherBase',
|
|
18
|
-
`<h1>Your One-Time Password Reset Code:<h1>
|
|
19
|
-
<h2>${resetToken}<h2>
|
|
20
|
-
<p>Visit <a href="https://www.notherbase.com/the-front/keeper">notherbase.com/the-front/keeper</a> to finish changing your password.</p>`);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
10
|
/**
|
|
24
11
|
* Sends an email. WIP
|
|
25
12
|
* @param {String} toEmail Email Address to send to.
|
|
@@ -56,4 +43,4 @@ const send = async (toEmail, subject, html, name = "NotherBase") => {
|
|
|
56
43
|
return sent;
|
|
57
44
|
}
|
|
58
45
|
|
|
59
|
-
export default {
|
|
46
|
+
export default { send };
|
package/notherbase-fs.js
CHANGED
|
@@ -36,7 +36,8 @@ class NotherBaseFS {
|
|
|
36
36
|
this.app.use(express.json({
|
|
37
37
|
extended: true,
|
|
38
38
|
inflate: true,
|
|
39
|
-
type: 'application/x-www-form-urlencoded'
|
|
39
|
+
type: 'application/x-www-form-urlencoded',
|
|
40
|
+
limit: '50mb'
|
|
40
41
|
}));
|
|
41
42
|
|
|
42
43
|
//be safe, needs to be before session
|
|
@@ -80,8 +81,8 @@ class NotherBaseFS {
|
|
|
80
81
|
//enable cookies
|
|
81
82
|
this.app.use((req, res, next) => {
|
|
82
83
|
this.bases[req.hosting].session(req, res, next);
|
|
83
|
-
});
|
|
84
|
-
|
|
84
|
+
});
|
|
85
|
+
|
|
85
86
|
// allows us to get static files like css
|
|
86
87
|
this.app.use((req, res, next) => {
|
|
87
88
|
this.bases[req.hosting].static(req, res, next);
|
|
@@ -89,15 +90,32 @@ class NotherBaseFS {
|
|
|
89
90
|
this.app.use(express.static(`${__dirname}/public`));
|
|
90
91
|
|
|
91
92
|
//provide database access and etc to use in routes
|
|
92
|
-
this.app.use((req, res, next) => {
|
|
93
|
+
this.app.use(async (req, res, next) => {
|
|
93
94
|
req.globals = globals;
|
|
94
95
|
req.db = Models;
|
|
96
|
+
req.user = req.session?.currentUser ? await req.db.Spirit.recallOne("user", null, { username: req.session.currentUser }) : null;
|
|
95
97
|
req.lock = false;
|
|
96
98
|
// enables sessions only if the protocol is https and we are in production, or if we are in development
|
|
97
99
|
req.sessionsEnabled = (process.env.PRODUCTION == "true" && req.secure) || process.env.PRODUCTION == "false";
|
|
98
100
|
next();
|
|
99
101
|
});
|
|
100
102
|
|
|
103
|
+
//destroy session if it is not authorized
|
|
104
|
+
this.app.use(async (req, res, next) => {
|
|
105
|
+
if (req.session.currentUser) {
|
|
106
|
+
if (req.user?.memory?.data?.sessions?.[req.session.id]) {
|
|
107
|
+
if (req.user.memory.data.sessions[req.session.id] < Date.now()) {
|
|
108
|
+
req.session.regenerate(() => {});
|
|
109
|
+
delete req.user.memory.data.sessions[req.session.id];
|
|
110
|
+
await req.user.memory.save();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else req.session.regenerate(() => {});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
next();
|
|
117
|
+
});
|
|
118
|
+
|
|
101
119
|
//spirit world routes
|
|
102
120
|
this.app.use("/s", this.spiritWorld.router);
|
|
103
121
|
|
package/package.json
CHANGED
package/public/js/base.js
CHANGED
|
@@ -220,4 +220,16 @@ class Base {
|
|
|
220
220
|
let response = await Base.commune("importData", { password, data: text });
|
|
221
221
|
return response;
|
|
222
222
|
}
|
|
223
|
+
|
|
224
|
+
sendOTP = async (email) => {
|
|
225
|
+
let response = await Base.commune("sendOTP");
|
|
226
|
+
|
|
227
|
+
return response;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
changeEmail = async (password, email) => {
|
|
231
|
+
let response = await Base.commune("changeEmail", { password, email });
|
|
232
|
+
|
|
233
|
+
return response;
|
|
234
|
+
}
|
|
223
235
|
}
|
package/test/the-front/index.ejs
CHANGED
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
<input type="file" id="fileInput">
|
|
26
26
|
<!-- password input -->
|
|
27
27
|
<input type="test" id="password" placeholder="pass">
|
|
28
|
+
<button onclick="sendOTP()">Get OTP</button>
|
|
29
|
+
<input type="text" id="email">
|
|
30
|
+
<button onclick="changeEmail()">Change Email</button>
|
|
28
31
|
|
|
29
32
|
<hr>
|
|
30
33
|
|
|
@@ -99,12 +102,12 @@
|
|
|
99
102
|
let test = new Test();
|
|
100
103
|
|
|
101
104
|
let downloadData = async () => {
|
|
102
|
-
let res = base.downloadData();
|
|
105
|
+
let res = await base.downloadData();
|
|
103
106
|
console.log(res.message);
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
let deleteData = async () => {
|
|
107
|
-
let res = base.deleteData($('#password').val());
|
|
110
|
+
let res = await base.deleteData($('#password').val());
|
|
108
111
|
console.log(res.message);
|
|
109
112
|
}
|
|
110
113
|
|
|
@@ -114,4 +117,16 @@
|
|
|
114
117
|
let res = await base.importData(pass, file);
|
|
115
118
|
console.log(res.message);
|
|
116
119
|
}
|
|
120
|
+
|
|
121
|
+
let sendOTP = async () => {
|
|
122
|
+
let res = await base.sendOTP();
|
|
123
|
+
console.log(res.message);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let changeEmail = async () => {
|
|
127
|
+
let pass = $('#password').val();
|
|
128
|
+
let email = $('#email').val();
|
|
129
|
+
let res = await base.changeEmail(pass, email);
|
|
130
|
+
console.log(res.message);
|
|
131
|
+
}
|
|
117
132
|
</script>
|