diff --git a/src/server/backend/db/mysqldb.js b/src/server/backend/db/mysqldb.js
index 85c717f..f1b66e8 100644
--- a/src/server/backend/db/mysqldb.js
+++ b/src/server/backend/db/mysqldb.js
@@ -55,7 +55,7 @@ class SQLDB {
if ( error ) throw error;
if ( results[ 0 ][ '@@default_storage_engine' ] !== 'InnoDB' ) return 'DB HAS TO USE InnoDB!';
} );
- this.sqlConnection.query( 'CREATE TABLE libreevent_users ( account_id INT ( 10 ) NOT NULL AUTO_INCREMENT, email TINYTEXT NOT NULL, pass TEXT, name TEXT, first_name TEXT, two_fa TINYTEXT, user_data VARCHAR( 60000 ), PRIMARY KEY ( account_id ) ) ENGINE=INNODB;', ( error ) => {
+ this.sqlConnection.query( 'CREATE TABLE libreevent_users ( account_id INT ( 10 ) NOT NULL AUTO_INCREMENT, email TINYTEXT NOT NULL, pass TEXT, name TEXT, first_name TEXT, two_fa TINYTEXT, user_data VARCHAR( 60000 ), mail_confirmed TINYTEXT, marketing_ok TINYTEXT, PRIMARY KEY ( account_id ) ) ENGINE=INNODB;', ( error ) => {
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
this.sqlConnection.query( 'CREATE TABLE libreevent_orders ( order_id INT ( 10 ) NOT NULL AUTO_INCREMENT, account_id INT ( 10 ) NOT NULL, seats VARCHAR( 60000 ), PRIMARY KEY ( order_id ), FOREIGN KEY ( account_id ) REFERENCES libreevent_users( account_id ) ) ENGINE=INNODB;', ( error ) => {
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
diff --git a/src/server/backend/userRoutes.js b/src/server/backend/userRoutes.js
index 9ace9a2..184462e 100644
--- a/src/server/backend/userRoutes.js
+++ b/src/server/backend/userRoutes.js
@@ -18,6 +18,7 @@ const bodyParser = require( 'body-parser' );
let responseObjects = {};
let authOk = {};
+let mailTokens = {};
module.exports = ( app, settings ) => {
app.get( '/user/details', ( request, response ) => {
@@ -134,21 +135,23 @@ module.exports = ( app, settings ) => {
app.get( '/user/logout', ( request, response ) => {
request.session.loggedInUser = false;
+ request.session.username = '';
response.send( 'logoutOk' );
} );
app.post( '/user/signup', bodyParser.json(), ( request, response ) => {
- // TODO: Make sure that user does not exist yet first and if user
- // exists, send back info that it is that way
- // TODO: check for 2fa
// TODO: Send mail to confirm email address
if ( request.body.password && request.body.password === request.body.password2 && request.body.firstName && request.body.name && request.body.country && request.body.mail ) {
db.checkDataAvailability( 'users', 'email', request.body.mail ).then( status => {
if ( status ) {
response.send( 'exists' );
} else {
- db.writeDataSimple( 'users', 'email', request.body.mail, { 'pass': pwdmanager.hashPassword( request.body.password ), 'first_name': request.body.firstName, 'name': request.body.name, 'two_fa': String( request.body.twoFA ), 'user_data': { 'country': request.body.country } } ).then( () => {
- response.send( 'ok' );
+ pwdmanager.hashPassword( request.body.password ).then( hash => {
+ db.writeDataSimple( 'users', 'email', request.body.mail, { 'email': request.body.mail, 'pass': hash, 'first_name': request.body.firstName, 'name': request.body.name, 'two_fa': 'disabled', 'user_data': JSON.stringify( { 'country': request.body.country } ) } ).then( () => {
+ request.session.loggedInUser = true;
+ request.session.username = request.body.mail;
+ response.send( 'ok' );
+ } );
} );
}
} );
@@ -156,4 +159,37 @@ module.exports = ( app, settings ) => {
response.status( 400 ).send( 'incomplete' );
}
} );
+
+ app.get( '/user/signup/confirm', ( request, response ) => {
+ if ( Object.keys( mailTokens ).includes( request.query.token ) ) {
+ request.session.username = mailTokens[ request.query.token ];
+ db.writeDataSimple( 'users', 'email', request.session.username, { 'mail_confirmed': 'true' } );
+ delete mailTokens[ request.query.token ];
+ if ( settings.twoFA === 'allow' ) {
+ response.sendFile( path.join( __dirname + '/../ui/en/signup/allowTwoFA.html' ) );
+ } else if ( settings.twoFA === 'enforce' ) {
+ response.sendFile( path.join( __dirname + '/../ui/en/signup/enforceTwoFA.html' ) );
+ } else {
+ response.sendFile( path.join( __dirname + '/../ui/en/signup/disallowTwoFA.html' ) );
+ }
+ } else {
+ response.sendFile( path.join( __dirname + '/../ui/en/signup/invalid.html' ) );
+ }
+ } );
+
+ app.post( '/user/settings/:setting', bodyParser.json(), ( request, response ) => {
+ let call = request.params.setting;
+ if ( request.session.username ) {
+ if ( call === '2fa' ) {
+ db.writeDataSimple( 'users', 'email', request.session.username, { 'two_fa': request.body.twoFA } );
+ response.send( 'ok' );
+ }
+ } else {
+ response.send( 'unauthorised' );
+ }
+ } );
+
+ app.get( '/settings/2fa', ( request, response ) => {
+ response.send( settings.twoFA );
+ } );
};
\ No newline at end of file
diff --git a/src/server/config/settings.config.json b/src/server/config/settings.config.json
index 5e0d7af..7322949 100644
--- a/src/server/config/settings.config.json
+++ b/src/server/config/settings.config.json
@@ -1,6 +1,7 @@
{
"init": true,
- "twoFA": "enhanced",
+ "twoFA": "allow",
+ "twoFAMode": "enhanced",
"db": "mysql",
"payments": "stripe",
"name": "libreevent",
diff --git a/src/server/ui/en/signup/allowTwoFA.html b/src/server/ui/en/signup/allowTwoFA.html
new file mode 100644
index 0000000..9e6db51
--- /dev/null
+++ b/src/server/ui/en/signup/allowTwoFA.html
@@ -0,0 +1,122 @@
+
+
+
+
+
+ Email verification
+
+
+
+
+
Email Verification
+
This website requires you to use Two-Factor Authentication. Please choose your mode below. By default, the enhanced mode is enabled which requires you to type a 6-character code into a field after confirming the mail address. You can change this setting at any point later.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/server/ui/en/signup/disallowTwoFA.html b/src/server/ui/en/signup/disallowTwoFA.html
new file mode 100644
index 0000000..e0f47c6
--- /dev/null
+++ b/src/server/ui/en/signup/disallowTwoFA.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+ Email Verification Successful
+
+
+
+
+
Email Verification Successful
+
Thank you! Your email address has been verified successfully. You may now close this tab.
+
+
+
\ No newline at end of file
diff --git a/src/server/ui/en/signup/enforceTwoFA.html b/src/server/ui/en/signup/enforceTwoFA.html
new file mode 100644
index 0000000..4771818
--- /dev/null
+++ b/src/server/ui/en/signup/enforceTwoFA.html
@@ -0,0 +1,123 @@
+
+
+
+
+
+ Email verification
+
+
+
+
+
Email Verification
+
We strongly encourage you to enable Two-Factor authentication for your account. Below you have the choice between not enabling it, enabling a mode where you just have to click the link in the email and you're in (simple) and a mode where you have to click the link in the mail and confirm the login by typing the code displayed on the main window (enhanced).
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/server/ui/en/signup/invalid.html b/src/server/ui/en/signup/invalid.html
new file mode 100644
index 0000000..dbe69cb
--- /dev/null
+++ b/src/server/ui/en/signup/invalid.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+ Email Verification Token Invalid
+
+
+
+
+
Email Verification Token Invalid
+
The email verification token you specified is invalid. Please check that it is correct and try again. If it still doesn't work, please request a new one by logging into your account and clicking "resend email verification token"
+
+
+
\ No newline at end of file
diff --git a/src/webapp/main/notes.md b/src/webapp/main/notes.md
index 356d677..bc2da71 100644
--- a/src/webapp/main/notes.md
+++ b/src/webapp/main/notes.md
@@ -5,6 +5,8 @@
- create function that parses DB every 15 minutes and clears out junk
+- Require user to confirm email before purchasing
+
- Create password changing endpoint (to reset forgotten pwd)
- Add Admin profile (page to change account settings per person like changing pwd)
diff --git a/src/webapp/main/src/views/user/AccountView.vue b/src/webapp/main/src/views/user/AccountView.vue
index 473a28a..bc119db 100644
--- a/src/webapp/main/src/views/user/AccountView.vue
+++ b/src/webapp/main/src/views/user/AccountView.vue
@@ -50,7 +50,11 @@
res.json().then( data => {
if ( data.status ) {
this.accountData = data.data;
- console.log( data.data );
+ if ( !data.data.mail_confirmed ) {
+ setTimeout( () => {
+ this.$refs.notification.createNotification( 'Your account is unverified. Please confirm your email using the link we have sent to your email!', 20, 'info', 'normal' );
+ }, 1000 );
+ }
} else {
this.userStore.setUserAuth( false );
this.userStore.setUser2fa( false );
diff --git a/src/webapp/main/src/views/user/SignupView.vue b/src/webapp/main/src/views/user/SignupView.vue
index f3f12fe..a5f1b8e 100644
--- a/src/webapp/main/src/views/user/SignupView.vue
+++ b/src/webapp/main/src/views/user/SignupView.vue
@@ -108,9 +108,13 @@
console.log( res );
res.text().then( status => {
if ( status === 'ok' ) {
- this.userStore.setUserAuth( true );
- this.$router.push( sessionStorage.getItem( 'redirect' ) ?? '/account' );
- sessionStorage.removeItem( 'redirect' );
+ this.$refs.notification.cancelNotification( progress );
+ this.$refs.notification.createNotification( 'Signed up successfully. We have sent you an email. Please confirm it to finish sign-up', 5, 'ok', 'normal' );
+ setTimeout( () => {
+ this.userStore.setUserAuth( true );
+ this.$router.push( sessionStorage.getItem( 'redirect' ) ?? '/account' );
+ sessionStorage.removeItem( 'redirect' );
+ }, 5000 );
} else if ( status === 'exists' ) {
this.$refs.notification.cancelNotification( progress );
this.$refs.notification.createNotification( 'An account with this email address already exists. Please log in using it.', 5, 'error', 'normal' );