notherbase-fs 4.5.3 → 4.5.5
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/package.json +1 -1
- package/server/user.js +232 -165
package/package.json
CHANGED
package/server/user.js
CHANGED
|
@@ -28,12 +28,17 @@ export default class User {
|
|
|
28
28
|
* @param {Object} res An Express.js response.
|
|
29
29
|
*/
|
|
30
30
|
logout = async (req, res) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
try {
|
|
32
|
+
if (loginCheck(req, res)) {
|
|
33
|
+
delete req.user?.data?.sessions[req.session.id];
|
|
34
|
+
await req.user.commit();
|
|
35
|
+
await req.session?.destroy();
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
success(res, "Logged out.");
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.log(error);
|
|
41
|
+
fail(res, "Server error");
|
|
37
42
|
}
|
|
38
43
|
}
|
|
39
44
|
|
|
@@ -43,49 +48,57 @@ export default class User {
|
|
|
43
48
|
* @param {Object} res An Express.js response.
|
|
44
49
|
*/
|
|
45
50
|
changePassword = async (req, res) => {
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
try {
|
|
52
|
+
if (loginCheck(req, res)) {
|
|
53
|
+
let spirit = await req.Spirit.findOne({ service: "user", "data.username": req.session.currentUser });
|
|
54
|
+
console.log(spirit);
|
|
55
|
+
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
if (check(res, spirit, "User not found!") &&
|
|
58
|
+
check(res, req.body.newPassword === req.body.confirmation, "New password and confirmation must match!") &&
|
|
59
|
+
check(res, req.body.oldPassword != req.body.newPassword, "New password must be different from the old one."))
|
|
60
|
+
{
|
|
61
|
+
let passResult = await bcrypt.compare(req.body.oldPassword, spirit.data.password);
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
await spirit.commit();
|
|
65
|
-
|
|
66
|
-
success(res, "Password changed successfully!");
|
|
63
|
+
if (check(res, passResult, "Old password incorrect.")) {
|
|
64
|
+
const salt = await bcrypt.genSalt(10);
|
|
65
|
+
const hash = await bcrypt.hash(req.body.newPassword, salt);
|
|
66
|
+
|
|
67
|
+
spirit.data.password = hash;
|
|
68
|
+
await spirit.commit();
|
|
69
|
+
|
|
70
|
+
success(res, "Password changed successfully!");
|
|
71
|
+
}
|
|
67
72
|
}
|
|
68
73
|
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.log(error);
|
|
76
|
+
fail(res, "Server error");
|
|
69
77
|
}
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
validatePassword = async (req, password, user) => {
|
|
73
|
-
|
|
74
|
-
if (password
|
|
75
|
-
if (
|
|
76
|
-
user.data.otp.expires
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
try {
|
|
82
|
+
if (password && user?.data?.otp) {
|
|
83
|
+
if (password == user.data.otp.code) {
|
|
84
|
+
if (Date.now() < user.data.otp.expires) {
|
|
85
|
+
user.data.otp.expires = 0;
|
|
86
|
+
await user.commit();
|
|
87
|
+
return "Authenticated.";
|
|
88
|
+
}
|
|
89
|
+
else return "One-time password expired.";
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
let passResult = await bcrypt.compare(req.body.password, user.data.password);
|
|
93
|
+
if (passResult) return "Authenticated.";
|
|
94
|
+
else return "Password doesn't match the username.";
|
|
79
95
|
}
|
|
80
|
-
else return "One-time password expired.";
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
let passResult = await bcrypt.compare(req.body.password, user.data.password);
|
|
84
|
-
if (passResult) return "Authenticated.";
|
|
85
|
-
else return "Password doesn't match the username.";
|
|
86
96
|
}
|
|
97
|
+
else return "Password error.";
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.log(error);
|
|
100
|
+
fail(res, "Server error");
|
|
87
101
|
}
|
|
88
|
-
else return "Password error.";
|
|
89
102
|
}
|
|
90
103
|
|
|
91
104
|
/**
|
|
@@ -94,29 +107,30 @@ export default class User {
|
|
|
94
107
|
* @param {Object} res An Express.js response.
|
|
95
108
|
*/
|
|
96
109
|
changeEmail = async (req, res) => {
|
|
97
|
-
|
|
98
|
-
|
|
110
|
+
try {
|
|
111
|
+
if (loginCheck(req, res)) {
|
|
112
|
+
let spirit = await req.Spirit.findOne({ service: "user", "data.username": req.session.currentUser });
|
|
99
113
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
await spirit.commit();
|
|
114
|
-
|
|
115
|
-
success(res, "Email changed successfully!");
|
|
114
|
+
if (check(res, spirit, "User not found!") &&
|
|
115
|
+
check(res, req.body.email, "New email must be provided."))
|
|
116
|
+
{
|
|
117
|
+
let result = await this.validatePassword(req, req.body.password, spirit);
|
|
118
|
+
if (result == "Authenticated.") {
|
|
119
|
+
let other = await req.Spirit.findOne({ service: "user", "data.email": req.body.email });
|
|
120
|
+
|
|
121
|
+
if (check(res, !other, "Email already in use!")) {
|
|
122
|
+
spirit.data.email = req.body.email;
|
|
123
|
+
await spirit.commit();
|
|
124
|
+
|
|
125
|
+
success(res, "Email changed successfully!");
|
|
126
|
+
}
|
|
116
127
|
}
|
|
128
|
+
else fail(res, result);
|
|
117
129
|
}
|
|
118
|
-
else fail(res, result);
|
|
119
130
|
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.log(error);
|
|
133
|
+
fail(res, "Server error");
|
|
120
134
|
}
|
|
121
135
|
}
|
|
122
136
|
|
|
@@ -126,26 +140,31 @@ export default class User {
|
|
|
126
140
|
* @param {Object} res An Express.js response.
|
|
127
141
|
*/
|
|
128
142
|
sendOneTimePassword = async (req, res) => {
|
|
129
|
-
|
|
130
|
-
|
|
143
|
+
try {
|
|
144
|
+
if (loginCheck(req, res)) {
|
|
145
|
+
let spirit = await req.Spirit.findOne({ service: "user", "data.username": req.session.currentUser });
|
|
131
146
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
if (check(res, spirit, "User not found!")) {
|
|
148
|
+
let otp = Math.floor(100000 + Math.random() * 900000);
|
|
149
|
+
spirit.data.otp = {
|
|
150
|
+
code: otp,
|
|
151
|
+
expires: Date.now() + 1000 * 60 * 15
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
await spirit.commit();
|
|
140
155
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
156
|
+
await req.SendMail.send(spirit.data.email, 'One Time Password for NotherBase',
|
|
157
|
+
`<h1>Your One-Time Password:<h1>
|
|
158
|
+
<h2>${otp}<h2>
|
|
159
|
+
<p>Visit <a href="https://www.notherbase.com/the-front/keeper">notherbase.com/the-front/keeper</a> to use your one-time password.</p>
|
|
160
|
+
<p>This one-time password expires in 15 minutes.<p>`);
|
|
161
|
+
|
|
162
|
+
success(res, "One-time password sent.");
|
|
163
|
+
}
|
|
148
164
|
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.log(error);
|
|
167
|
+
fail(res, "Server error");
|
|
149
168
|
}
|
|
150
169
|
}
|
|
151
170
|
|
|
@@ -155,30 +174,41 @@ export default class User {
|
|
|
155
174
|
* @param {Object} res An Express.js response.
|
|
156
175
|
*/
|
|
157
176
|
register = async (req, res) => {
|
|
158
|
-
|
|
159
|
-
check(res, req.body.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (check(res, !spirit, "Username already in use!")) {
|
|
164
|
-
const salt = await bcrypt.genSalt(10);
|
|
165
|
-
const hash = await bcrypt.hash(req.body.password, salt);
|
|
166
|
-
|
|
167
|
-
spirit = await req.Spirit.create("user", {
|
|
168
|
-
username: req.body.username,
|
|
169
|
-
password: hash,
|
|
170
|
-
authLevels: [ "Basic" ],
|
|
171
|
-
view: "compact",
|
|
172
|
-
email: "",
|
|
173
|
-
otp: {
|
|
174
|
-
code: "",
|
|
175
|
-
expires: 0
|
|
176
|
-
},
|
|
177
|
-
sessions: {}
|
|
178
|
-
});
|
|
177
|
+
try {
|
|
178
|
+
if (check(res, req.body.password.length > 10, "Password must be >10 characters long.") &&
|
|
179
|
+
check(res, req.body.username.length > 2, "Username too short."))
|
|
180
|
+
{
|
|
181
|
+
let spirit = await req.Spirit.findOne({ service: "user", "data.username": req.body.username });
|
|
179
182
|
|
|
180
|
-
|
|
183
|
+
if (check(res, !spirit, "Username already in use!")) {
|
|
184
|
+
const salt = await bcrypt.genSalt(10);
|
|
185
|
+
const hash = await bcrypt.hash(req.body.password, salt);
|
|
186
|
+
|
|
187
|
+
spirit = new req.Spirit({
|
|
188
|
+
service:"user",
|
|
189
|
+
_lastUpdate: Date.now(),
|
|
190
|
+
data: {
|
|
191
|
+
username: req.body.username,
|
|
192
|
+
password: hash,
|
|
193
|
+
authLevels: [ "Basic" ],
|
|
194
|
+
view: "compact",
|
|
195
|
+
email: "",
|
|
196
|
+
otp: {
|
|
197
|
+
code: "",
|
|
198
|
+
expires: 0
|
|
199
|
+
},
|
|
200
|
+
sessions: {}
|
|
201
|
+
},
|
|
202
|
+
backups: []
|
|
203
|
+
});
|
|
204
|
+
await spirit.save();
|
|
205
|
+
|
|
206
|
+
success(res, "Registration successful!");
|
|
207
|
+
}
|
|
181
208
|
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.log(error);
|
|
211
|
+
fail(res, "Server error");
|
|
182
212
|
}
|
|
183
213
|
}
|
|
184
214
|
|
|
@@ -188,32 +218,37 @@ export default class User {
|
|
|
188
218
|
* @param {Object} res An Express.js response.
|
|
189
219
|
*/
|
|
190
220
|
login = async (req, res) => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
spirit.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
let result = await this.validatePassword(req, req.body.password, spirit);
|
|
209
|
-
if (result === "Authenticated.") {
|
|
210
|
-
req.session.currentUser = req.body.username;
|
|
211
|
-
if (typeof spirit.data.sessions !== "object" || Array.isArray(spirit.data.sessions)) spirit.data.sessions = {};
|
|
212
|
-
spirit.data.sessions[req.session.id] = Date.now() + 1000 * 60 * 60 * 24 * 28; // 28 days
|
|
221
|
+
try {
|
|
222
|
+
let spirit = await req.Spirit.findOne({ service: "user", "data.username": req.body.username });
|
|
223
|
+
if (check(res, spirit, "User not found.")) {
|
|
224
|
+
spirit.data = {
|
|
225
|
+
username: "",
|
|
226
|
+
password: "",
|
|
227
|
+
authLevels: [ "Basic" ],
|
|
228
|
+
view: "compact",
|
|
229
|
+
email: "",
|
|
230
|
+
otp: {
|
|
231
|
+
code: "",
|
|
232
|
+
expires: 0
|
|
233
|
+
},
|
|
234
|
+
sessions: {},
|
|
235
|
+
...spirit.data
|
|
236
|
+
}
|
|
213
237
|
await spirit.commit();
|
|
214
|
-
|
|
238
|
+
|
|
239
|
+
let result = await this.validatePassword(req, req.body.password, spirit);
|
|
240
|
+
if (result === "Authenticated.") {
|
|
241
|
+
req.session.currentUser = req.body.username;
|
|
242
|
+
if (typeof spirit.data.sessions !== "object" || Array.isArray(spirit.data.sessions)) spirit.data.sessions = {};
|
|
243
|
+
spirit.data.sessions[req.session.id] = Date.now() + 1000 * 60 * 60 * 24 * 28; // 28 days
|
|
244
|
+
await spirit.commit();
|
|
245
|
+
success(res, "Login successful!", req.body.username);
|
|
246
|
+
}
|
|
247
|
+
else fail(res, result);
|
|
215
248
|
}
|
|
216
|
-
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.log(error);
|
|
251
|
+
fail(res, "Server error");
|
|
217
252
|
}
|
|
218
253
|
}
|
|
219
254
|
|
|
@@ -223,22 +258,27 @@ export default class User {
|
|
|
223
258
|
* @param {Object} res An Express.js response.
|
|
224
259
|
*/
|
|
225
260
|
deletePermanently = async (req, res) => {
|
|
226
|
-
|
|
227
|
-
|
|
261
|
+
try {
|
|
262
|
+
if (loginCheck(req, res)) {
|
|
263
|
+
let spirit = await req.Spirit.findOne({ service: "user", "data.username": req.session.currentUser });
|
|
228
264
|
|
|
229
|
-
|
|
230
|
-
|
|
265
|
+
if (check(res, spirit, "User not found.")) {
|
|
266
|
+
let passResult = await bcrypt.compare(req.body.password, spirit.data.password);
|
|
231
267
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (check(res, deleted > 0, "No account deleted")) {
|
|
236
|
-
await req.session.destroy();
|
|
268
|
+
if (check(res, passResult, "Password doesn't match the username.")) {
|
|
269
|
+
let deleted = await req.Spirit.deleteMany({ service: "user", "data.username": req.session.currentUser });
|
|
237
270
|
|
|
238
|
-
|
|
271
|
+
if (check(res, deleted > 0, "No account deleted")) {
|
|
272
|
+
await req.session.destroy();
|
|
273
|
+
|
|
274
|
+
success(res, "Account deleted.");
|
|
275
|
+
}
|
|
239
276
|
}
|
|
240
277
|
}
|
|
241
278
|
}
|
|
279
|
+
} catch (error) {
|
|
280
|
+
console.log(error);
|
|
281
|
+
fail(res, "Server error");
|
|
242
282
|
}
|
|
243
283
|
}
|
|
244
284
|
|
|
@@ -248,74 +288,101 @@ export default class User {
|
|
|
248
288
|
* @param {Object} res An Express.js response.
|
|
249
289
|
*/
|
|
250
290
|
getInfo = async (req, res) => {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
291
|
+
try {
|
|
292
|
+
if (loginCheck(req, res)) {
|
|
293
|
+
let user = await req.Spirit.findOne({ service: "user", "data.username": req.session.currentUser });
|
|
294
|
+
|
|
295
|
+
if (check(res, user, "Account not found!")) {
|
|
296
|
+
success(res, "Info found", {
|
|
297
|
+
username: user.data.username
|
|
298
|
+
});
|
|
299
|
+
}
|
|
258
300
|
}
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.log(error);
|
|
303
|
+
fail(res, "Server error");
|
|
259
304
|
}
|
|
260
305
|
}
|
|
261
306
|
|
|
262
307
|
//download all spirit data belonging to the user
|
|
263
308
|
downloadData = async (req, res) => {
|
|
264
|
-
|
|
265
|
-
|
|
309
|
+
try {
|
|
310
|
+
if (loginCheck(req, res)) {
|
|
311
|
+
let user = await req.Spirit.findOne({ service: "user", "data.username": req.session.currentUser });
|
|
266
312
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
313
|
+
if (check(res, user, "Account not found!")) {
|
|
314
|
+
let data = await req.Spirit.find({ parent: user._id });
|
|
315
|
+
let dataToDownload = data.map(d => d);
|
|
270
316
|
|
|
271
|
-
|
|
317
|
+
successJSON(res, "Data Downloaded", dataToDownload);
|
|
318
|
+
}
|
|
272
319
|
}
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.log(error);
|
|
322
|
+
fail(res, "Server error");
|
|
273
323
|
}
|
|
274
324
|
}
|
|
275
325
|
|
|
276
326
|
//delete all spirit data belonging to the user
|
|
277
327
|
deleteAlldata = async (req, res) => {
|
|
278
|
-
|
|
279
|
-
|
|
328
|
+
try {
|
|
329
|
+
if (loginCheck(req, res)) {
|
|
330
|
+
let user = await req.Spirit.findOne({ service: "user", "data.username": req.session.currentUser });
|
|
280
331
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
332
|
+
if (check(res, user, "Account not found!")) {
|
|
333
|
+
if (check(res, req.body.password, "Password error.")) {
|
|
334
|
+
let passResult = await bcrypt.compare(req.body.password, user.data.password);
|
|
284
335
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
336
|
+
if (check(res, passResult, "Password doesn't match the username.")) {
|
|
337
|
+
let deleted = await req.Spirit.deleteMany({ parent: user._id });
|
|
338
|
+
if (check(res, deleted > 0, "No data deleted")) {
|
|
339
|
+
success(res, "Data Deleted", deleted);
|
|
340
|
+
}
|
|
289
341
|
}
|
|
290
342
|
}
|
|
291
343
|
}
|
|
292
344
|
}
|
|
345
|
+
} catch (error) {
|
|
346
|
+
console.log(error);
|
|
347
|
+
fail(res, "Server error");
|
|
293
348
|
}
|
|
294
349
|
}
|
|
295
350
|
|
|
296
351
|
// import spirit data from a JSON file
|
|
297
352
|
importData = async (req, res) => {
|
|
298
|
-
|
|
299
|
-
|
|
353
|
+
try {
|
|
354
|
+
if (loginCheck(req, res)) {
|
|
355
|
+
let user = await req.Spirit.findOne({ service: "user", "data.username": req.session.currentUser });
|
|
300
356
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
357
|
+
if (check(res, user, "Account not found!")) {
|
|
358
|
+
if (check(res, req.body.password, "Password error.")) {
|
|
359
|
+
let passResult = await bcrypt.compare(req.body.password, user.data.password);
|
|
304
360
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
361
|
+
if (check(res, passResult, "Password doesn't match the username.")) {
|
|
362
|
+
let data = JSON.parse(req.body.data);
|
|
363
|
+
let imported = 0;
|
|
364
|
+
for (let i = 0; i < data.length; i++) {
|
|
365
|
+
if (data[i].parent != null) {
|
|
366
|
+
let spirit = new req.Spirit({
|
|
367
|
+
service: data[i].service,
|
|
368
|
+
_lastUpdate: data[i]._lastUpdate,
|
|
369
|
+
data: data[i].data,
|
|
370
|
+
parent: user._id,
|
|
371
|
+
backups: data[i].backups || []
|
|
372
|
+
});
|
|
373
|
+
await spirit.save();
|
|
374
|
+
if (spirit) imported++;
|
|
375
|
+
}
|
|
312
376
|
}
|
|
313
|
-
}
|
|
314
377
|
|
|
315
|
-
|
|
378
|
+
success(res, "Data Imported", imported);
|
|
379
|
+
}
|
|
316
380
|
}
|
|
317
381
|
}
|
|
318
382
|
}
|
|
383
|
+
} catch (error) {
|
|
384
|
+
console.log(error);
|
|
385
|
+
fail(res, "Server error");
|
|
319
386
|
}
|
|
320
387
|
}
|
|
321
388
|
}
|