mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 05:14:23 +00:00
working 2fa system
This commit is contained in:
@@ -8,8 +8,10 @@
|
||||
*/
|
||||
|
||||
const token = require( '../backend/token.js' );
|
||||
// let createSSRApp = require( 'vue' ).createSSRApp;
|
||||
// let renderToString = require( 'vue/server-renderer' ).renderToString;
|
||||
let createSSRApp = require( 'vue' ).createSSRApp;
|
||||
let renderToString = require( 'vue/server-renderer' ).renderToString;
|
||||
const fs = require( 'fs' );
|
||||
const path = require( 'path' );
|
||||
|
||||
class TwoFA {
|
||||
constructor () {
|
||||
@@ -61,6 +63,22 @@ class TwoFA {
|
||||
} else if ( this.tokenStore[ token ]?.mode === 'enhanced' ) return 'enhanced';
|
||||
else return 'invalid';
|
||||
}
|
||||
|
||||
async generateTwoFAMail ( token, ip, domain, pageName ) {
|
||||
const app = createSSRApp( {
|
||||
data() {
|
||||
return {
|
||||
token: token,
|
||||
ip: ip,
|
||||
host: domain,
|
||||
pageName: pageName,
|
||||
};
|
||||
},
|
||||
template: '' + fs.readFileSync( path.join( __dirname + '/twoFAMail.html' ) )
|
||||
} );
|
||||
|
||||
return await renderToString( app );
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TwoFA;
|
||||
@@ -12,13 +12,15 @@ const pwdmanager = require( './pwdmanager.js' );
|
||||
const auth = require( './2fa.js' );
|
||||
const twoFA = new auth();
|
||||
const path = require( 'path' );
|
||||
const mail = require( '../backend/mail/mailSender.js' );
|
||||
const mailManager = new mail();
|
||||
|
||||
let responseObjects = {};
|
||||
let authOk = {};
|
||||
|
||||
module.exports = ( app, settings ) => {
|
||||
/*
|
||||
Admin login route that checks the password
|
||||
Admin login route that checks the password
|
||||
*/
|
||||
|
||||
app.post( '/admin/auth', ( request, response ) => {
|
||||
@@ -26,18 +28,26 @@ module.exports = ( app, settings ) => {
|
||||
pwdmanager.checkpassword( request.body.mail, request.body.password ).then( data => {
|
||||
request.session.username = request.body.mail;
|
||||
if ( data ) {
|
||||
// TODO: Send mails
|
||||
request.session.username = request.body.mail;
|
||||
// TODO: Check if user has 2fa enabled
|
||||
if ( settings.twoFA === 'standard' ) {
|
||||
let tok = twoFA.registerStandardAuthentication()[ 'token' ];
|
||||
request.session.token = tok;
|
||||
console.log( 'http://localhost:8081/admin/2fa?token=' + tok );
|
||||
response.send( { 'status': '2fa' } );
|
||||
( async () => {
|
||||
let tok = twoFA.registerStandardAuthentication()[ 'token' ];
|
||||
let ipRetrieved = request.headers[ 'x-forwarded-for' ];
|
||||
let ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : request.connection.remoteAddress;
|
||||
mailManager.sendMail( request.body.mail, await twoFA.generateTwoFAMail( tok, ip, settings.yourDomain, settings.name ), 'Verify admin account login', settings.mailSender );
|
||||
request.session.token = tok;
|
||||
response.send( { 'status': '2fa' } );
|
||||
} )();
|
||||
} else if ( settings.twoFA === 'enhanced' ) {
|
||||
let res = twoFA.registerEnhancedAuthentication();
|
||||
console.log( 'http://localhost:8081/admin/2fa?token=' + res.token );
|
||||
request.session.token = res.token;
|
||||
response.send( { 'status': '2fa+', 'code': res.code } );
|
||||
( async () => {
|
||||
let res = twoFA.registerEnhancedAuthentication();
|
||||
let ipRetrieved = request.headers[ 'x-forwarded-for' ];
|
||||
let ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : request.connection.remoteAddress;
|
||||
mailManager.sendMail( request.body.mail, await twoFA.generateTwoFAMail( res.token, ip, settings.yourDomain, settings.name ), 'Verify admin account login', settings.mailSender );
|
||||
request.session.token = res.token;
|
||||
response.send( { 'status': '2fa+', 'code': res.code } );
|
||||
} )();
|
||||
} else {
|
||||
request.session.loggedInUser = true;
|
||||
response.send( { 'status': 'ok' } );
|
||||
|
||||
@@ -21,7 +21,17 @@ const db = require( '../backend/db/db.js' );
|
||||
module.exports.checkpassword = ( username, password ) => {
|
||||
return new Promise( resolve => {
|
||||
db.getDataSimple( 'admin', 'email', username ).then( data => {
|
||||
resolve( bcrypt.compareSync( password, data ) );
|
||||
if ( data ) {
|
||||
if ( data[ 0 ] ) {
|
||||
bcrypt.compare( password, data[ 0 ].pass ).then( res => {
|
||||
resolve( res );
|
||||
} );
|
||||
} else {
|
||||
resolve( false );
|
||||
}
|
||||
} else {
|
||||
resolve( false );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
70
src/server/admin/twoFAMail.html
Normal file
70
src/server/admin/twoFAMail.html
Normal file
@@ -0,0 +1,70 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Two-Factor Authentication</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
width: 100%;
|
||||
height: 800px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 80%;
|
||||
height: 90%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ip {
|
||||
color: rgb(94, 94, 94);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 70vw;
|
||||
}
|
||||
|
||||
.verify {
|
||||
padding: 20px 30px;
|
||||
background-color: rgb(0, 7, 87);
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
transition: 0.5s all;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.verify:hover {
|
||||
background-color: rgb(0, 12, 139);
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 999px) {
|
||||
.logo {
|
||||
width: 20vw;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 40vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<img :src="host + '/otherAssets/logo.png'" alt="Logo" class="logo">
|
||||
<h1>Welcome back!</h1>
|
||||
<p>It looks like someone is trying to sign in to your admin account at {{ pageName }}. If it was you, please click the button below to confirm the login. If not, please <a :href="host + '/admin/profile/settings'">change</a> your password immediately or have it changed by the root account!</p>
|
||||
<p class="ip">Logging in from IP {{ ip }}.</p>
|
||||
<a :href="host + '/admin/2fa?token=' + token" class="verify">Verify</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,13 +8,16 @@
|
||||
*/
|
||||
|
||||
const token = require( '../token.js' );
|
||||
// let createSSRApp = require( 'vue' ).createSSRApp;
|
||||
// let renderToString = require( 'vue/server-renderer' ).renderToString;
|
||||
let createSSRApp = require( 'vue' ).createSSRApp;
|
||||
let renderToString = require( 'vue/server-renderer' ).renderToString;
|
||||
const fs = require( 'fs' );
|
||||
const path = require( 'path' );
|
||||
|
||||
class TwoFA {
|
||||
constructor () {
|
||||
this.tokenStore = {};
|
||||
this.references = {};
|
||||
this.pwdChangeTokens = {};
|
||||
}
|
||||
|
||||
registerStandardAuthentication () {
|
||||
@@ -61,6 +64,29 @@ class TwoFA {
|
||||
} else if ( this.tokenStore[ token ]?.mode === 'enhanced' ) return 'enhanced';
|
||||
else return 'invalid';
|
||||
}
|
||||
|
||||
generatePwdChangeToken () {
|
||||
// TODO: Gen token and store in store
|
||||
return 'test';
|
||||
}
|
||||
|
||||
async generateTwoFAMail ( token, ip, domain, pageName ) {
|
||||
const tok = this.generatePwdChangeToken();
|
||||
const app = createSSRApp( {
|
||||
data() {
|
||||
return {
|
||||
token: token,
|
||||
ip: ip,
|
||||
host: domain,
|
||||
pageName: pageName,
|
||||
pwdChangeToken: tok,
|
||||
};
|
||||
},
|
||||
template: '' + fs.readFileSync( path.join( __dirname + '/twoFAMail.html' ) )
|
||||
} );
|
||||
|
||||
return await renderToString( app );
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TwoFA;
|
||||
@@ -19,9 +19,17 @@ const db = require( '../db/db.js' );
|
||||
module.exports.checkpassword = function checkpassword ( email, password ) {
|
||||
return new Promise( resolve => {
|
||||
db.getDataSimple( 'user', 'email', email ).then( data => {
|
||||
bcrypt.compare( password, data ).then( data => {
|
||||
resolve( data );
|
||||
} );
|
||||
if ( data ) {
|
||||
if ( data[ 0 ] ) {
|
||||
bcrypt.compare( password, data[ 0 ].pass ).then( res => {
|
||||
resolve( res );
|
||||
} );
|
||||
} else {
|
||||
resolve( false );
|
||||
}
|
||||
} else {
|
||||
resolve( false );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
70
src/server/backend/credentials/twoFAMail.html
Normal file
70
src/server/backend/credentials/twoFAMail.html
Normal file
@@ -0,0 +1,70 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Two-Factor Authentication</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
width: 100%;
|
||||
height: 800px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 80%;
|
||||
height: 90%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ip {
|
||||
color: rgb(94, 94, 94);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 70vw;
|
||||
}
|
||||
|
||||
.verify {
|
||||
padding: 20px 30px;
|
||||
background-color: rgb(0, 7, 87);
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
transition: 0.5s all;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.verify:hover {
|
||||
background-color: rgb(0, 12, 139);
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 999px) {
|
||||
.logo {
|
||||
width: 20vw;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 40vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<img :src="host + '/otherAssets/logo.png'" alt="Logo" class="logo">
|
||||
<h1>Welcome back!</h1>
|
||||
<p>It looks like someone is trying to sign in to your account at {{ pageName }}. If it was you, please click the button below to confirm the login. If not, please <a :href="host + '/account/changePassword?token=' + pwdChangeToken">change</a> your password immediately.</p>
|
||||
<p class="ip">Logging in from IP {{ ip }}.</p>
|
||||
<a :href="host + '/user/2fa?token=' + token" class="verify">Verify</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -55,11 +55,11 @@ 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, street TEXT, house_number TINYTEXT, country TEXT, phone TEXT, name TEXT, first_name TEXT, data VARCHAR( 10000 ), 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, street TEXT, house_number TINYTEXT, country TEXT, phone TEXT, name TEXT, first_name TEXT, two_fa 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;
|
||||
this.sqlConnection.query( 'CREATE TABLE libreevent_admin ( account_id INT NOT NULL AUTO_INCREMENT, email TINYTEXT, pass TEXT, permissions VARCHAR( 1000 ), PRIMARY KEY ( account_id ) );', ( error ) => {
|
||||
this.sqlConnection.query( 'CREATE TABLE libreevent_admin ( account_id INT NOT NULL AUTO_INCREMENT, email TINYTEXT, pass TEXT, permissions VARCHAR( 1000 ), username TINYTEXT, two_fa TINYTEXT, PRIMARY KEY ( account_id ) );', ( error ) => {
|
||||
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
|
||||
this.sqlConnection.query( 'CREATE TABLE libreevent_temp ( entry_id INT NOT NULL AUTO_INCREMENT, user_id TINYTEXT, data VARCHAR( 60000 ), timestamp TINYTEXT, PRIMARY KEY ( entry_id ) );', ( error ) => {
|
||||
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
|
||||
|
||||
@@ -12,32 +12,61 @@ const pwdmanager = require( './credentials/pwdmanager.js' );
|
||||
const auth = require( './credentials/2fa.js' );
|
||||
const twoFA = new auth();
|
||||
const path = require( 'path' );
|
||||
const mail = require( './mail/mailSender.js' );
|
||||
const mailManager = new mail();
|
||||
|
||||
let responseObjects = {};
|
||||
let authOk = {};
|
||||
|
||||
module.exports = ( app, settings ) => {
|
||||
app.post( '/api/reserveTicket', ( request, response ) => {
|
||||
db.getData( 'test', request.body );
|
||||
response.send( 'ok' );
|
||||
app.get( '/user/details', ( request, response ) => {
|
||||
if ( request.session.loggedInUser ) {
|
||||
db.getDataSimple( 'users', 'email', request.session.username ).then( data => {
|
||||
if ( data[ 0 ] ) {
|
||||
let dat = data[ 0 ];
|
||||
delete dat[ 'pass' ];
|
||||
response.send( { 'data': dat, 'status': true } );
|
||||
} else {
|
||||
response.send( { 'data': 'This user does not exist', 'status': false } );
|
||||
}
|
||||
} ).catch( () => {
|
||||
response.send( { 'data': 'There was an error reading data from the database. If this error persists, please contact the administrators', 'status': false } );
|
||||
} );
|
||||
} else {
|
||||
response.status( 403 ).send( path.join( __dirname + '/../ui/en/errors/403.html' ) );
|
||||
}
|
||||
} );
|
||||
|
||||
app.get( '/test/user', ( req, res ) => {
|
||||
req.session.loggedInUser = true;
|
||||
req.session.username = 'info@janishutz.com';
|
||||
res.send( 'ok' );
|
||||
} );
|
||||
|
||||
app.post( '/user/login', ( request, response ) => {
|
||||
if ( request.body.mail && request.body.password ) {
|
||||
pwdmanager.checkpassword( request.body.mail, request.body.password ).then( data => {
|
||||
request.session.username = request.body.mail;
|
||||
// TODO: Check if user has 2fa enabled
|
||||
if ( data ) {
|
||||
// TODO: Send mails
|
||||
if ( settings.twoFA === 'standard' ) {
|
||||
let tok = twoFA.registerStandardAuthentication()[ 'token' ];
|
||||
request.session.token = tok;
|
||||
console.log( 'http://localhost:8081/user/2fa?token=' + tok );
|
||||
response.send( { 'status': '2fa' } );
|
||||
( async () => {
|
||||
let tok = twoFA.registerStandardAuthentication()[ 'token' ];
|
||||
let ipRetrieved = request.headers[ 'x-forwarded-for' ];
|
||||
let ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : request.connection.remoteAddress;
|
||||
mailManager.sendMail( request.body.mail, await twoFA.generateTwoFAMail( tok, ip, settings.yourDomain, settings.name ), 'Verify login', settings.mailSender );
|
||||
request.session.token = tok;
|
||||
response.send( { 'status': '2fa' } );
|
||||
} )();
|
||||
} else if ( settings.twoFA === 'enhanced' ) {
|
||||
let res = twoFA.registerEnhancedAuthentication();
|
||||
console.log( 'http://localhost:8081/user/2fa?token=' + res.token );
|
||||
request.session.token = res.token;
|
||||
response.send( { 'status': '2fa+', 'code': res.code } );
|
||||
( async () => {
|
||||
let res = twoFA.registerEnhancedAuthentication();
|
||||
let ipRetrieved = request.headers[ 'x-forwarded-for' ];
|
||||
let ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : request.connection.remoteAddress;
|
||||
mailManager.sendMail( request.body.mail, await twoFA.generateTwoFAMail( res.token, ip, settings.yourDomain, settings.name ), 'Verify login', settings.mailSender );
|
||||
request.session.token = res.token;
|
||||
response.send( { 'status': '2fa+', 'code': res.code } );
|
||||
} )();
|
||||
} else {
|
||||
request.session.loggedInUser = true;
|
||||
response.send( { 'status': 'ok' } );
|
||||
@@ -108,6 +137,11 @@ module.exports = ( app, settings ) => {
|
||||
} );
|
||||
|
||||
app.post( '/user/signup', ( request, response ) => {
|
||||
// TODO: Make sure that user does not exist yet first and if user
|
||||
// exists, send back info that it is that way
|
||||
response.send( 'ok' );
|
||||
db.writeDataSimple( 'users', 'email', request.body.email, { 'pass': pwdmanager.hashPassword( request.query.password ), 'street': '', 'house_number': '', 'country': request.query.country, 'first_name': request.query.firstName, 'name': request.query.name, 'two_fa': String( request.query.twoFA ) } ).then( res => {
|
||||
console.log( res );
|
||||
} );
|
||||
} );
|
||||
};
|
||||
@@ -4,5 +4,6 @@
|
||||
"db": "mysql",
|
||||
"payments": "stripe",
|
||||
"name": "libreevent",
|
||||
"yourDomain": "http://localhost:8081"
|
||||
"yourDomain": "http://localhost:8081",
|
||||
"mailSender": "libreevent <info@libreevent.janishutz.com>"
|
||||
}
|
||||
209
src/server/package-lock.json
generated
209
src/server/package-lock.json
generated
@@ -21,7 +21,8 @@
|
||||
"nodemailer": "^6.9.3",
|
||||
"serve-favicon": "^2.5.0",
|
||||
"serve-static": "^1.15.0",
|
||||
"stripe": "^12.14.0"
|
||||
"stripe": "^12.14.0",
|
||||
"vue": "^3.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "^8.8.2",
|
||||
@@ -59,6 +60,17 @@
|
||||
"yocto-queue": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
|
||||
"integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
@@ -104,8 +116,7 @@
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.18",
|
||||
@@ -242,6 +253,108 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.4.tgz",
|
||||
"integrity": "sha512-CukZhumInROvLq3+b5gLev+vgpsIqC2D0deQr/yS1WnxvmYLlJXZpaQrQiseMY+6xusl79E04UjWoqyr+t1/Ew=="
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
|
||||
"integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.21.3",
|
||||
"@vue/shared": "3.3.4",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz",
|
||||
"integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.3.4",
|
||||
"@vue/shared": "3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz",
|
||||
"integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.20.15",
|
||||
"@vue/compiler-core": "3.3.4",
|
||||
"@vue/compiler-dom": "3.3.4",
|
||||
"@vue/compiler-ssr": "3.3.4",
|
||||
"@vue/reactivity-transform": "3.3.4",
|
||||
"@vue/shared": "3.3.4",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.0",
|
||||
"postcss": "^8.1.10",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz",
|
||||
"integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.3.4",
|
||||
"@vue/shared": "3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz",
|
||||
"integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity-transform": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz",
|
||||
"integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.20.15",
|
||||
"@vue/compiler-core": "3.3.4",
|
||||
"@vue/shared": "3.3.4",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz",
|
||||
"integrity": "sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.3.4",
|
||||
"@vue/shared": "3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz",
|
||||
"integrity": "sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==",
|
||||
"dependencies": {
|
||||
"@vue/runtime-core": "3.3.4",
|
||||
"@vue/shared": "3.3.4",
|
||||
"csstype": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz",
|
||||
"integrity": "sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.3.4",
|
||||
"@vue/shared": "3.3.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
|
||||
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
@@ -615,6 +728,11 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
@@ -774,6 +892,11 @@
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||
},
|
||||
"node_modules/etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
@@ -1429,6 +1552,17 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.2",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz",
|
||||
"integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
@@ -1625,6 +1759,23 @@
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
@@ -1848,6 +1999,38 @@
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.27",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
||||
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.6",
|
||||
"picocolors": "^1.0.0",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
@@ -2159,6 +2342,14 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-support": {
|
||||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
@@ -2397,6 +2588,18 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz",
|
||||
"integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.3.4",
|
||||
"@vue/compiler-sfc": "3.3.4",
|
||||
"@vue/runtime-dom": "3.3.4",
|
||||
"@vue/server-renderer": "3.3.4",
|
||||
"@vue/shared": "3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
|
||||
@@ -54,7 +54,8 @@
|
||||
"nodemailer": "^6.9.3",
|
||||
"serve-favicon": "^2.5.0",
|
||||
"serve-static": "^1.15.0",
|
||||
"stripe": "^12.14.0"
|
||||
"stripe": "^12.14.0",
|
||||
"vue": "^3.3.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "test.js"
|
||||
|
||||
@@ -1,6 +1,24 @@
|
||||
const sql = require( './backend/db/mysqldb.js' );
|
||||
const sqlDB = new sql();
|
||||
|
||||
const db = require( './backend/db/db.js' );
|
||||
|
||||
sqlDB.connect();
|
||||
// sqlDB.resetDB();
|
||||
sqlDB.setupDB();
|
||||
|
||||
sqlDB.resetDB();
|
||||
|
||||
setTimeout( () => {
|
||||
sqlDB.setupDB();
|
||||
|
||||
setTimeout( () => {
|
||||
db.writeDataSimple( 'admin', 'email', 'info@janishutz.com', { 'email': 'info@janishutz.com', 'pass': '$2b$05$ElMYWoMjk7567lXkIkee.e.6cxCrWU4gkfuNLB8gmGYLQQPm7gT3O', 'username': 'jhutz' } );
|
||||
}, 1000 );
|
||||
|
||||
setTimeout( () => {
|
||||
db.writeDataSimple( 'user', 'email', 'info@janishutz.com', { 'email': 'info@janishutz.com', 'pass': '$2b$05$ElMYWoMjk7567lXkIkee.e.6cxCrWU4gkfuNLB8gmGYLQQPm7gT3O', 'name': 'Hutz', 'first_name': 'Janis', 'two_fa': 'true' } );
|
||||
}, 1000 );
|
||||
|
||||
setTimeout( () => {
|
||||
db.writeDataSimple( 'admin', 'email', 'info@janishutz.com', { 'email': 'info@janishutz.com', 'pass': '$2b$05$ElMYWoMjk7567lXkIkee.e.6cxCrWU4gkfuNLB8gmGYLQQPm7gT3O', 'username': 'jhutz', 'permissions': JSON.stringify( { 'test': true } ), 'two_fa': true } );
|
||||
}, 2000 );
|
||||
}, 1000 );
|
||||
@@ -1,9 +1,16 @@
|
||||
# Account view:
|
||||
- Maybe add multi-language support
|
||||
|
||||
- make pricing groups changeable in UI (event categories)
|
||||
|
||||
- Create password changing endpoint (to reset forgotten pwd)
|
||||
- Add Admin profile (page to change account settings per person like changing pwd)
|
||||
|
||||
|
||||
- Fix text field overflow (text too big for box)
|
||||
- Other optimisation for seat plan editor
|
||||
|
||||
|
||||
- Implement Permission system
|
||||
|
||||
- Seat numbering
|
||||
|
||||
@@ -116,6 +116,15 @@ export default [
|
||||
transition: 'scale'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/guest',
|
||||
name: 'guestPurchase',
|
||||
component: () => import( '@/views/purchasing/GuestPurchaseView.vue' ),
|
||||
meta: {
|
||||
title: 'Guest purchase - ',
|
||||
transition: 'scale'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/admin/seatplan',
|
||||
name: 'adminSeatplanEditor',
|
||||
|
||||
@@ -32,64 +32,72 @@
|
||||
...mapStores( useUserStore ),
|
||||
},
|
||||
created () {
|
||||
if ( !!window.EventSource ) {
|
||||
setTimeout( () => {
|
||||
let startNotification = this.$refs.notification.createNotification( 'Connecting to status service', 20, 'progress', 'normal' );
|
||||
let source = new EventSource( localStorage.getItem( 'url' ) + '/admin/2fa/check', { withCredentials: true } );
|
||||
|
||||
let self = this;
|
||||
if ( this.userStore.getAdminTwoFACompliant ) {
|
||||
if ( !!window.EventSource ) {
|
||||
setTimeout( () => {
|
||||
let startNotification = this.$refs.notification.createNotification( 'Connecting to status service', 20, 'progress', 'normal' );
|
||||
let source = new EventSource( localStorage.getItem( 'url' ) + '/admin/2fa/check', { withCredentials: true } );
|
||||
|
||||
let self = this;
|
||||
|
||||
source.onmessage = ( e ) => {
|
||||
if ( e.data === 'authenticated' ) {
|
||||
self.userStore.setAdminAuth( true );
|
||||
self.$router.push( '/admin' );
|
||||
console.log( e.data );
|
||||
source.onmessage = ( e ) => {
|
||||
if ( e.data === 'authenticated' ) {
|
||||
self.userStore.setAdminAuth( true );
|
||||
self.$router.push( '/admin' );
|
||||
console.log( e.data );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source.onopen = e => {
|
||||
self.$refs.notification.createNotification( 'Connected to status service', 5, 'ok', 'normal' );
|
||||
self.$refs.notification.cancelNotification( startNotification );
|
||||
};
|
||||
|
||||
source.addEventListener( 'error', function(e) {
|
||||
if ( e.eventPhase == EventSource.CLOSED ) source.close();
|
||||
|
||||
if ( e.target.readyState == EventSource.CLOSED ) {
|
||||
console.log( e );
|
||||
source.onopen = e => {
|
||||
self.$refs.notification.createNotification( 'Connected to status service', 5, 'ok', 'normal' );
|
||||
self.$refs.notification.cancelNotification( startNotification );
|
||||
self.$refs.notification.createNotification( 'Could not connect to status service', 5, 'error', 'normal' );
|
||||
}
|
||||
}, false)
|
||||
}, 300 );
|
||||
} else {
|
||||
setTimeout( () => {
|
||||
this.$refs.notification.createNotification( 'Unsupported browser detected. Redirection might take longer to occur!', 20, 'warning', 'normal' );
|
||||
}, 300 );
|
||||
// ping server every 5s to check if logged in
|
||||
this.serverPing = setInterval( () => {
|
||||
fetch( '/admin/2fa/ping' ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.json().then( data => {
|
||||
if ( data ) {
|
||||
if ( data.status === 'ok' ) {
|
||||
this.userStore.setUserAuth( true );
|
||||
this.$router.push( sessionStorage.getItem( 'redirect' ) ?? '/account' );
|
||||
};
|
||||
|
||||
source.addEventListener( 'error', function(e) {
|
||||
if ( e.eventPhase == EventSource.CLOSED ) source.close();
|
||||
|
||||
if ( e.target.readyState == EventSource.CLOSED ) {
|
||||
console.log( e );
|
||||
self.$refs.notification.cancelNotification( startNotification );
|
||||
self.$refs.notification.createNotification( 'Could not connect to status service', 5, 'error', 'normal' );
|
||||
}
|
||||
}, false)
|
||||
}, 300 );
|
||||
} else {
|
||||
setTimeout( () => {
|
||||
this.$refs.notification.createNotification( 'Unsupported browser detected. Redirection might take longer to occur!', 20, 'warning', 'normal' );
|
||||
}, 300 );
|
||||
// ping server every 5s to check if logged in
|
||||
this.serverPing = setInterval( () => {
|
||||
fetch( '/admin/2fa/ping' ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.json().then( data => {
|
||||
if ( data ) {
|
||||
if ( data.status === 'ok' ) {
|
||||
this.userStore.setUserAuth( true );
|
||||
this.$router.push( sessionStorage.getItem( 'redirect' ) ?? '/account' );
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
} else {
|
||||
console.error( 'Request failed' );
|
||||
} );
|
||||
} else {
|
||||
console.error( 'Request failed' );
|
||||
this.$refs.notification.createNotification( 'We are sorry, but an error occurred. You will not be redirected automatically', 300, 'error', 'normal' );
|
||||
}
|
||||
} ).catch( error => {
|
||||
console.error( error );
|
||||
this.$refs.notification.createNotification( 'We are sorry, but an error occurred. You will not be redirected automatically', 300, 'error', 'normal' );
|
||||
}
|
||||
} ).catch( error => {
|
||||
console.error( error );
|
||||
this.$refs.notification.createNotification( 'We are sorry, but an error occurred. You will not be redirected automatically', 300, 'error', 'normal' );
|
||||
} );
|
||||
}, 5000 );
|
||||
} );
|
||||
}, 5000 );
|
||||
}
|
||||
let code = sessionStorage.getItem( '2faCode' ) ? sessionStorage.getItem( '2faCode' ) : '';
|
||||
this.code = { '1': code.slice( 0, 3 ), '2': code.substring( 3 ) };
|
||||
} else {
|
||||
if ( this.userStore.getAdminAuthenticated ) {
|
||||
this.$router.push( '/admin' );
|
||||
} else {
|
||||
this.$router.push( '/admin/login' );
|
||||
}
|
||||
}
|
||||
let code = sessionStorage.getItem( '2faCode' ) ? sessionStorage.getItem( '2faCode' ) : '';
|
||||
this.code = { '1': code.slice( 0, 3 ), '2': code.substring( 3 ) };
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -5,4 +5,16 @@
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
-->
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Guest purchase</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -217,6 +217,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
loadData () {
|
||||
// TODO: Also load the customer data from server!
|
||||
this.cartNotEmpty = false;
|
||||
let cart = JSON.parse( localStorage.getItem( 'cart' ) );
|
||||
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Account</h1>
|
||||
|
||||
<p>Welcome, {{ accountData.first_name }} {{ accountData.name }}!</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
Email
|
||||
</td>
|
||||
<td>
|
||||
{{ accountData.email }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<notifications ref="notification" location="topright" size="bigger"></notifications>
|
||||
<popups ref="popups" size="big" @data="data => { savePwd( data ) }"></popups>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -10,4 +22,50 @@
|
||||
nav {
|
||||
display: initial;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
import { mapStores } from 'pinia';
|
||||
import notifications from '@/components/notifications/notifications.vue';
|
||||
import popups from '@/components/notifications/popups.vue';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
accountData: {},
|
||||
}
|
||||
},
|
||||
components: {
|
||||
notifications,
|
||||
popups,
|
||||
},
|
||||
computed: {
|
||||
...mapStores( useUserStore )
|
||||
},
|
||||
created () {
|
||||
// TODO: Also get all orders of user (using join functions)
|
||||
fetch( '/user/details' ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.json().then( data => {
|
||||
if ( data.status ) {
|
||||
this.accountData = data.data;
|
||||
console.log( data.data );
|
||||
} else {
|
||||
this.userStore.setUserAuth( false );
|
||||
this.userStore.setUser2fa( false );
|
||||
this.$router.push( '/login' );
|
||||
}
|
||||
} );
|
||||
} else if ( res.status === 403 ) {
|
||||
this.userStore.setUserAuth( false );
|
||||
this.userStore.setUser2fa( false );
|
||||
this.$router.push( '/login' );
|
||||
}
|
||||
} );
|
||||
if ( this.userStore.getUserTwoFACompliant ) {
|
||||
this.userStore.setUser2fa( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -33,62 +33,70 @@
|
||||
...mapStores( useUserStore ),
|
||||
},
|
||||
created () {
|
||||
if ( !!window.EventSource ) {
|
||||
setTimeout( () => {
|
||||
let startNotification = this.$refs.notification.createNotification( 'Connecting to status service', 20, 'progress', 'normal' );
|
||||
let source = new EventSource( localStorage.getItem( 'url' ) + '/user/2fa/check', { withCredentials: true } );
|
||||
|
||||
let self = this;
|
||||
if ( this.userStore.getUserTwoFACompliant ) {
|
||||
if ( !!window.EventSource ) {
|
||||
setTimeout( () => {
|
||||
let startNotification = this.$refs.notification.createNotification( 'Connecting to status service', 20, 'progress', 'normal' );
|
||||
let source = new EventSource( localStorage.getItem( 'url' ) + '/user/2fa/check', { withCredentials: true } );
|
||||
|
||||
let self = this;
|
||||
|
||||
source.onmessage = ( e ) => {
|
||||
if ( e.data === 'authenticated' ) {
|
||||
self.userStore.setUserAuth( true );
|
||||
self.$router.push( sessionStorage.getItem( 'redirect' ) ?? '/account' );
|
||||
source.onmessage = ( e ) => {
|
||||
if ( e.data === 'authenticated' ) {
|
||||
self.userStore.setUserAuth( true );
|
||||
self.$router.push( sessionStorage.getItem( 'redirect' ) ?? '/account' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source.onopen = e => {
|
||||
self.$refs.notification.createNotification( 'Connected to status service', 5, 'ok', 'normal' );
|
||||
self.$refs.notification.cancelNotification( startNotification );
|
||||
};
|
||||
|
||||
source.addEventListener( 'error', function( e ) {
|
||||
if ( e.eventPhase == EventSource.CLOSED ) source.close();
|
||||
|
||||
if ( e.target.readyState == EventSource.CLOSED ) {
|
||||
source.onopen = e => {
|
||||
self.$refs.notification.createNotification( 'Connected to status service', 5, 'ok', 'normal' );
|
||||
self.$refs.notification.cancelNotification( startNotification );
|
||||
self.$refs.notification.createNotification( 'Could not connect to status service', 5, 'error', 'normal' );
|
||||
}
|
||||
}, false)
|
||||
}, 300 );
|
||||
} else {
|
||||
setTimeout( () => {
|
||||
this.$refs.notification.createNotification( 'Unsupported browser detected. Redirection might take longer to occur!', 20, 'warning', 'normal' );
|
||||
}, 300 );
|
||||
// ping server every 5s to check if logged in
|
||||
this.serverPing = setInterval( () => {
|
||||
fetch( '/user/2fa/ping' ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.json().then( data => {
|
||||
if ( data ) {
|
||||
if ( data.status === 'ok' ) {
|
||||
this.userStore.setUserAuth( true );
|
||||
this.$router.push( sessionStorage.getItem( 'redirect' ) ?? '/account' );
|
||||
};
|
||||
|
||||
source.addEventListener( 'error', function( e ) {
|
||||
if ( e.eventPhase == EventSource.CLOSED ) source.close();
|
||||
|
||||
if ( e.target.readyState == EventSource.CLOSED ) {
|
||||
self.$refs.notification.cancelNotification( startNotification );
|
||||
self.$refs.notification.createNotification( 'Could not connect to status service', 5, 'error', 'normal' );
|
||||
}
|
||||
}, false)
|
||||
}, 300 );
|
||||
} else {
|
||||
setTimeout( () => {
|
||||
this.$refs.notification.createNotification( 'Unsupported browser detected. Redirection might take longer to occur!', 20, 'warning', 'normal' );
|
||||
}, 300 );
|
||||
// ping server every 5s to check if logged in
|
||||
this.serverPing = setInterval( () => {
|
||||
fetch( '/user/2fa/ping' ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.json().then( data => {
|
||||
if ( data ) {
|
||||
if ( data.status === 'ok' ) {
|
||||
this.userStore.setUserAuth( true );
|
||||
this.$router.push( sessionStorage.getItem( 'redirect' ) ?? '/account' );
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
} else {
|
||||
console.error( 'Request failed' );
|
||||
} );
|
||||
} else {
|
||||
console.error( 'Request failed' );
|
||||
this.$refs.notification.createNotification( 'We are sorry, but an error occurred. You will not be redirected automatically', 300, 'error', 'normal' );
|
||||
}
|
||||
} ).catch( error => {
|
||||
console.error( error );
|
||||
this.$refs.notification.createNotification( 'We are sorry, but an error occurred. You will not be redirected automatically', 300, 'error', 'normal' );
|
||||
}
|
||||
} ).catch( error => {
|
||||
console.error( error );
|
||||
this.$refs.notification.createNotification( 'We are sorry, but an error occurred. You will not be redirected automatically', 300, 'error', 'normal' );
|
||||
} );
|
||||
}, 5000 );
|
||||
} );
|
||||
}, 5000 );
|
||||
}
|
||||
let code = sessionStorage.getItem( '2faCode' ) ? sessionStorage.getItem( '2faCode' ) : '';
|
||||
this.code = { '1': code.slice( 0, 3 ), '2': code.substring( 3 ) };
|
||||
} else {
|
||||
if ( this.userStore.getUserAuthenticated ) {
|
||||
this.$router.push( '/account' );
|
||||
} else {
|
||||
this.$router.push( '/login' );
|
||||
}
|
||||
}
|
||||
let code = sessionStorage.getItem( '2faCode' ) ? sessionStorage.getItem( '2faCode' ) : '';
|
||||
this.code = { '1': code.slice( 0, 3 ), '2': code.substring( 3 ) };
|
||||
},
|
||||
unmounted() {
|
||||
clearInterval( this.serverPing );
|
||||
|
||||
@@ -21,7 +21,9 @@ In the database, all the userdata is stored. libreevent currently supports two d
|
||||
|
||||
Generally MySQL, except:
|
||||
- If your organisation is small and does only sell a few tickets at a time, the JSON based database works perfectly fine.
|
||||
- Your web hosting plan does not includes MySQL and you've got no access to MySQL in any other way. *NOTE: Free MySQL services should NEVER be used in such an application, as most hosting plans include MySQL which is much more reliable and if you lose access to the database, you can only access the root account and all other data (and therefore all user accounts) is lost.*
|
||||
- Your web hosting plan does not includes MySQL and you've got no access to MySQL in any other way. *NOTE: Free MySQL services should NEVER be used in such an application, as most hosting plans include MySQL which is much more reliable and if you lose access to the database, you can only access the root account and all other user data (and therefore all user accounts) is lost. The event data is always stored in JSON format as it is more efficient.*
|
||||
|
||||
**NOTE: The JSON database is really slow and should only be used if you have a small event where you expect to sell less than 5 ticket per minute! The amount of tickets sold per minute that the system can handle really depends on the speed of the server the website runs on.**
|
||||
|
||||
MySQL generally is more difficult to set up, but we'll run you through the process here to make the process easier for you. If you chose the JSON based database, skip ahead to the next chapter.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user