11var pluginObject = { } ,
22 { authenticator : GA } = require ( "otplib" ) ,
3- URL = require ( 'url' ) . URL ,
4- qrcode = require ( "qrcode" ) ,
53 countlyConfig = require ( '../../../frontend/express/config' ) ,
64 plugins = require ( '../../pluginManager.js' ) ,
75 apiUtils = require ( "../../../api/utils/utils.js" ) ,
86 members = require ( "../../../frontend/express/libs/members.js" ) ,
9- versionInfo = require ( "../../../frontend/express/version.info" ) ,
107 languages = require ( '../../../frontend/express/locale.conf' ) ,
118 preventBruteforce = require ( '../../../frontend/express/libs/preventBruteforce.js' ) ;
129
13- /**
14- @param {string } username - user identifier
15- @param {string } secret - base32 encoded 2FA secret
16- @param {function } callback - function to call with an error, if any, and a SVG string
17- */
18- function generateQRCode ( username , secret , callback ) {
19- var domain = versionInfo . company || versionInfo . title || "Countly" ;
20-
21- if ( domain === "Countly" ) {
22- try {
23- const apiURL = plugins . getConfig ( "api" ) . domain ;
24- if ( apiURL ) {
25- let parsedURL = new URL ( apiURL ) ;
26- domain = parsedURL . hostname ;
27- }
28- }
29- catch ( err ) {
30- console . log ( `Error parsing api URL: ${ err } ` ) ;
31- }
32- }
33-
34- qrcode . toString ( GA . keyuri ( username , domain , secret ) ,
35- { type : "svg" , color : { light : "#FFF0" } , errorCorrectionLevel : "L" } ,
36- callback ) ;
37- }
10+ const { generateQRCode } = require ( '../lib.js' ) ;
3811
3912( function ( plugin ) {
4013 plugin . init = function ( app , countlyDb ) {
@@ -81,7 +54,7 @@ function generateQRCode(username, secret, callback) {
8154 // everything is ok, let the user reset their password
8255 countlyDb . collection ( 'password_reset' ) . updateOne ( { prid : req . params . prid } , { $set : { two_factor_auth_passed : true } } , { } , function ( passwordResetUpdateErr ) {
8356 if ( passwordResetUpdateErr ) {
84- console . log ( `Error setting 2FA pass for password reset: ${ passwordResetUpdateErr } ` ) ;
57+ console . error ( `Error setting 2FA pass for password reset: ${ passwordResetUpdateErr } ` ) ;
8558 }
8659 next ( ) ;
8760 } ) ;
@@ -90,7 +63,7 @@ function generateQRCode(username, secret, callback) {
9063 // 2FA auth code was wrong, delete the password reset token
9164 countlyDb . collection ( 'password_reset' ) . deleteOne ( { prid : req . params . prid } , function ( passwordResetDelErr ) {
9265 if ( passwordResetDelErr ) {
93- console . log ( `Error deleting password reset: ${ passwordResetDelErr } ` ) ;
66+ console . error ( `Error deleting password reset: ${ passwordResetDelErr } ` ) ;
9467 }
9568 } ) ;
9669 res . redirect ( countlyConfig . path + '/forgot' ) ;
@@ -139,38 +112,36 @@ function generateQRCode(username, secret, callback) {
139112
140113 // modify login flow
141114 app . post ( countlyConfig . path + '/login' , function ( req , res , next ) {
142- members . verifyCredentials ( req . body . username , req . body . password , function ( member ) {
115+ members . verifyCredentials ( req . body . username , req . body . password , async function ( member ) {
143116 // if member exists and 2fa is enabled globally or for the user
144117 if ( member && ( member . two_factor_auth && member . two_factor_auth . enabled || plugins . getConfig ( "two-factor-auth" ) . globally_enabled ) ) {
145118 // if 2fa is not set up for the user
146119 if ( ( member . two_factor_auth === undefined || member . two_factor_auth . secret_token === undefined ) &&
147120 ( req . body . auth_code === undefined || req . body . secret_token === undefined ) ) {
148121 const secretToken = GA . generateSecret ( ) ;
149-
150- generateQRCode ( member . username , secretToken , function ( err , svg ) {
151- if ( err ) {
152- console . log ( `Error generating QR code: ${ err } ` ) ;
153- res . redirect ( countlyConfig . path + "/login?message=two-factor-auth.login.error" ) ;
154- }
155- else {
156- res . render ( "../../../plugins/two-factor-auth/frontend/public/templates/setup2fa" , {
157- cdn : countlyConfig . cdn || "" ,
158- countlyFavicon : req . countly . favicon ,
159- countlyPage : req . countly . page ,
160- countlyTitle : req . countly . title ,
161- csrf : req . csrfToken ( ) ,
162- inject_template : req . template ,
163- languages : languages ,
164- message : req . flash ( 'info' ) ,
165- path : countlyConfig . path || "" ,
166- themeFiles : req . themeFiles ,
167- username : req . body . username || "" ,
168- password : req . body . password || "" ,
169- secret_token : secretToken ,
170- qrcode_html : svg
171- } ) ;
172- }
173- } ) ;
122+ try {
123+ const svg = await generateQRCode ( member . username , secretToken , console . warn ) ;
124+ res . render ( "../../../plugins/two-factor-auth/frontend/public/templates/setup2fa" , {
125+ cdn : countlyConfig . cdn || "" ,
126+ countlyFavicon : req . countly . favicon ,
127+ countlyPage : req . countly . page ,
128+ countlyTitle : req . countly . title ,
129+ csrf : req . csrfToken ( ) ,
130+ inject_template : req . template ,
131+ languages : languages ,
132+ message : req . flash ( 'info' ) ,
133+ path : countlyConfig . path || "" ,
134+ themeFiles : req . themeFiles ,
135+ username : req . body . username || "" ,
136+ password : req . body . password || "" ,
137+ secret_token : secretToken ,
138+ qrcode_html : svg
139+ } ) ;
140+ }
141+ catch ( err ) {
142+ console . error ( "Error generating QR code" , err ) ;
143+ res . redirect ( countlyConfig . path + "/login?message=two-factor-auth.login.error" ) ;
144+ }
174145 }
175146 // else if user did not provide 2fa code (login flow first phase)
176147 else if ( ! req . body . auth_code ) {
@@ -208,7 +179,7 @@ function generateQRCode(username, secret, callback) {
208179 } ,
209180 function ( enableErr ) {
210181 if ( enableErr ) {
211- console . log ( `Error enabling 2FA for ${ member . username } : ${ enableErr . message } ` ) ;
182+ console . error ( `Error enabling 2FA for ${ member . username } : ${ enableErr . message } ` ) ;
212183 }
213184 else {
214185 plugins . callMethod ( "logAction" , { req : req , res : res , user : member , action : "two_factor_auth_enabled" , data : { } } ) ;
@@ -221,30 +192,29 @@ function generateQRCode(username, secret, callback) {
221192 else {
222193 // 2fa is being set up
223194 if ( req . body . secret_token ) {
224- generateQRCode ( member . username , req . body . secret_token , function ( err , svg ) {
225- if ( err ) {
226- console . log ( `Error generating QR code: ${ err } ` ) ;
227- res . redirect ( countlyConfig . path + "/login?message=two-factor-auth.login.error" ) ;
228- }
229- else {
230- res . render ( "../../../plugins/two-factor-auth/frontend/public/templates/setup2fa" , {
231- cdn : countlyConfig . cdn || "" ,
232- countlyFavicon : req . countly . favicon ,
233- countlyPage : req . countly . page ,
234- countlyTitle : req . countly . title ,
235- csrf : req . csrfToken ( ) ,
236- inject_template : req . template ,
237- languages : languages ,
238- message : req . flash ( 'info' ) ,
239- path : countlyConfig . path || "" ,
240- themeFiles : req . themeFiles ,
241- username : req . body . username || "" ,
242- password : req . body . password || "" ,
243- secret_token : req . body . secret_token ,
244- qrcode_html : svg
245- } ) ;
246- }
247- } ) ;
195+ try {
196+ const svg = await generateQRCode ( member . username , req . body . secret_token , console . warn ) ;
197+ res . render ( "../../../plugins/two-factor-auth/frontend/public/templates/setup2fa" , {
198+ cdn : countlyConfig . cdn || "" ,
199+ countlyFavicon : req . countly . favicon ,
200+ countlyPage : req . countly . page ,
201+ countlyTitle : req . countly . title ,
202+ csrf : req . csrfToken ( ) ,
203+ inject_template : req . template ,
204+ languages : languages ,
205+ message : req . flash ( 'info' ) ,
206+ path : countlyConfig . path || "" ,
207+ themeFiles : req . themeFiles ,
208+ username : req . body . username || "" ,
209+ password : req . body . password || "" ,
210+ secret_token : req . body . secret_token ,
211+ qrcode_html : svg
212+ } ) ;
213+ }
214+ catch ( err ) {
215+ console . error ( "Error generating QR code" , err ) ;
216+ res . redirect ( countlyConfig . path + "/login?message=two-factor-auth.login.error" ) ;
217+ }
248218 }
249219 // 2fa is already set up
250220 else {
@@ -268,7 +238,7 @@ function generateQRCode(username, secret, callback) {
268238 }
269239 }
270240 catch ( verifyErr ) {
271- console . log ( `Error verifying 2FA for ${ member . username } : ${ verifyErr . message } ` ) ;
241+ console . error ( `Error verifying 2FA for ${ member . username } : ${ verifyErr . message } ` ) ;
272242 res . redirect ( countlyConfig . path + "/login?message=two-factor-auth.login.code" ) ;
273243 }
274244 }
@@ -284,19 +254,6 @@ function generateQRCode(username, secret, callback) {
284254 // these variables are passed to countly.views.js
285255 // therefore the view / vars are loaded in the existing countly window
286256 plugin . renderDashboard = function ( params ) {
287- var secretToken = GA . generateSecret ( ) ;
288-
289- params . data . countlyGlobal [ "2fa_secret_token" ] = secretToken ;
290-
291- generateQRCode ( params . data . countlyGlobal . member . username , secretToken , function ( err , svg ) {
292- if ( err ) {
293- console . log ( `Error generating QR code: ${ err } ` ) ;
294- params . data . countlyGlobal [ "2fa_qrcode_html" ] = "<span>:(</span>" ;
295- }
296- else {
297- params . data . countlyGlobal [ "2fa_qrcode_html" ] = svg ;
298- }
299- } ) ;
300257 params . data . countlyGlobal [ "2fa_globally_enabled" ] = ! ! plugins . getConfig ( "two-factor-auth" ) . globally_enabled ;
301258 } ;
302259} ( pluginObject ) ) ;
0 commit comments