diff --git a/backend/models/Campaign.js b/backend/models/Campaign.js
index d946c243..06646ceb 100644
--- a/backend/models/Campaign.js
+++ b/backend/models/Campaign.js
@@ -1,6 +1,8 @@
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
+const crypto = require("crypto");
+
const CampaignSchema = new Schema({
name: {type: String, required: true},
description: {type: String},
@@ -12,14 +14,7 @@ const CampaignSchema = new Schema({
});
CampaignSchema.statics.generateInvite = function() {
- let possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTVWXYZ0123456789";
- let cod = '';
-
- for (let i = 0; i < 32; i++) {
- cod += possible.charAt(Math.floor(Math.random() * possible.length));
- }
-
- return cod;
+ return crypto.randomBytes(8).toString('base64url');
}
module.exports = mongoose.model('Campaign', CampaignSchema);
\ No newline at end of file
diff --git a/backend/models/User.js b/backend/models/User.js
index 9aeac942..46b5939e 100755
--- a/backend/models/User.js
+++ b/backend/models/User.js
@@ -9,6 +9,7 @@ const UserSchema = new Schema({
date: { type: Date, default: Date.now},
admin: {type: Boolean, default: false},
image: { type: String },
+ setupCode: { type: String },
settings: { type: Object }
});
diff --git a/backend/routes/admin.js b/backend/routes/admin.js
index 4082883e..015d297f 100644
--- a/backend/routes/admin.js
+++ b/backend/routes/admin.js
@@ -11,21 +11,6 @@ const User = require("../models/User");
router.post('/register', rateLimitMiddleware, (req, res) => {
User.findOne({admin: true}).then((data) => {
if(!data) {
- let {
- name,
- username,
- email,
- password
- } = req.body;
-
- if(!(name && username && email && password)){
- res.json({
- error: true,
- msg: "params"
- });
- return;
- }
-
User.findOne({username: username}).then((user) => {
if(user){
res.json({
diff --git a/backend/routes/user.js b/backend/routes/user.js
index e0b21077..fd5d92f9 100755
--- a/backend/routes/user.js
+++ b/backend/routes/user.js
@@ -7,6 +7,7 @@ const passport = require('passport');
const secret = require('../config/keys').secret;
const rateLimitMiddleware = require("../config/rate-limiter");
const { default: jwtDecode } = require('jwt-decode');
+const crypto = require("crypto");
const { isAdmin } = require('../config/middleware');
@@ -14,14 +15,47 @@ const User = require("../models/User");
const upload = require("../config/storage");
+// Admin registers new user
router.post('/register', isAdmin, (req, res) => {
+ let setupCode = crypto.randomBytes(64).toString('base64url');
+
+ let user = new User({
+ admin: false,
+ name: crypto.randomBytes(16).toString('base64url'),
+ username: crypto.randomBytes(16).toString('base64url'),
+ email: crypto.randomBytes(16).toString('base64url'),
+ setupCode
+ });
+
+ user.save().then(user => {
+ res.json({
+ status: "ok",
+ code: setupCode,
+ });
+ }).catch({status: "err", msg: "internal"})
+});
+
+// User gets if setup account exists given the query code
+router.get('/setup', (req, res) => {
+ User.findOne({setupCode: req.query.code}).then(user => {
+ if(user){
+ res.json({status: "ok", code: req.query.code});
+ }
+ res.json({status: "err", msg: "not-exists"});
+ }).catch(res.json({status: "err", msg: "internal"}));
+});
+
+// User posts the parameters of his new account given by admin
+router.post('/setup', rateLimitMiddleware, (req, res) => {
let {
name,
username,
- email
+ email,
+ password
} = req.body;
+ let setupCode = req.query.code;
- if(!(name && username && email)){
+ if(!(name && username && email && password && setupCode)){
res.json({
error: true,
msg: "params"
@@ -29,39 +63,36 @@ router.post('/register', isAdmin, (req, res) => {
return;
}
- User.findOne({username: username}).then((user) => {
- if(user){
- res.json({
- error: true,
- msg: "already-exists"
- });
- } else {
- User.findOne({email: email}).then((user) => {
- if(user){
- res.json({
- error: true,
- msg: "already-email"
- });
- } else {
- var user = new User({
- name: name,
- username: username,
- email: email,
- admin: true
- });
+ User.findOne({setupCode}).then((user) => {
+ User.findOne({email: email}).then((sameUser) => {
+ if(sameUser){
+ res.json({
+ error: true,
+ msg: "already-email"
+ });
+ } else {
+ bcrypt.genSalt(10, (err, salt) => {
+ bcrypt.hash(user.password, salt, (err, hash) => {
+ if(err) throw err;
+ user.password = hash;
+ user.username = username;
+ user.email = email;
+ user.setupCode = undefined;
- user.save().then(user => {
- res.json({
- status: "ok",
- user
- });
- })
- }
- }).catch((error) => { res.json({ error: true, msg: "Hi ha hagut un error intern, prova-ho més tard" }); return; });
- }
- }).catch((error) => { res.json({ error: true, msg: "Hi ha hagut un error intern, prova-ho més tard" }); return; });
+ user.save().then(user => {
+ res.json({
+ success: true
+ });
+ return;
+ }).catch((error) => { res.json({ error: true }); return; });
+ });
+ })
+ }
+ }).catch((error) => { res.json({ error: true, msg: "internal" }); return; });
+ }).catch((error) => { res.json({ error: true, msg: "internal" }); return; });
});
+// Login post
router.post('/login', rateLimitMiddleware, (req, res) => {
const username = req.body.username;
const password = req.body.password;
@@ -111,6 +142,7 @@ router.post('/login', rateLimitMiddleware, (req, res) => {
});
});
+// Upload avatar post
router.post("/upload-avatar", upload.single("image"), passport.authenticate('jwt', {session: false}), (req, res) => {
const imageName = req.file.filename;
diff --git a/client/src/services/Windows.js b/client/src/services/Windows.js
index 88742f1e..28747930 100644
--- a/client/src/services/Windows.js
+++ b/client/src/services/Windows.js
@@ -31,6 +31,7 @@ import PluginManagementWindow from '@/views/windows/settings/PluginManagementWin
import PluginWindow from '../views/windows/settings/PluginWindow.vue';
import FirstRegisterWindow from '../views/windows/FirstRegisterWindow.vue';
import RegisterUserWindow from '../views/windows/settings/RegisterUserWindow.vue';
+import CopyPendingUserWindow from '../views/windows/settings/CopyPendingUserWindow.vue';
let windowMap = {
test: ExampleWindow,
@@ -39,6 +40,7 @@ let windowMap = {
welcome: WelcomeWindow,
first_register: FirstRegisterWindow,
register_user: RegisterUserWindow,
+ copy_pending_user_window: CopyPendingUserWindow,
edit_profile: EditProfileWindow,
settings: SettingsWindow,
campaign_list: CampaignListWindow,
diff --git a/client/src/views/windows/EditProfileWindow.vue b/client/src/views/windows/EditProfileWindow.vue
index dc1948b3..51d8c8ef 100644
--- a/client/src/views/windows/EditProfileWindow.vue
+++ b/client/src/views/windows/EditProfileWindow.vue
@@ -8,12 +8,14 @@ import Api from '@/services/Api'
import BigIconTemplate from '../partials/BigIconTemplate.vue';
import { SetMinSize, SetResizable } from '../../services/Windows';
import { backendUrl } from '../../services/BackendURL';
+import { GetUser } from '../../services/User';
const props = defineProps(['data']);
const data = props.data;
const userIcon = ref("");
const handle = ref(null);
+const isAdmin = ref(false);
let id = data.id;
console.log(data);
@@ -26,6 +28,8 @@ onMounted(() => {
SetResizable(id, true);
SetMinSize(id, {width: 350, height: 280});
+ isAdmin.value = GetUser().admin;
+
Api().get('/user/retrieve-avatar?username=' + data.user.username).then((response) => {
if(response.data.image) userIcon.value = backendUrl + "public/" + response.data.image;
else userIcon.value = "public/img/def-avatar.jpg";
@@ -39,7 +43,9 @@ onMounted(() => {
Hola
+