@@ -17,11 +17,8 @@ packageJson('parse-dashboard', 'latest').then(latestPackage => {
1717 }
1818} ) ;
1919
20- function getMount ( req ) {
21- let url = req . url ;
22- let originalUrl = req . originalUrl ;
23- var mountPathLength = req . originalUrl . length - req . url . length ;
24- var mountPath = req . originalUrl . slice ( 0 , mountPathLength ) ;
20+ function getMount ( mountPath ) {
21+ mountPath = mountPath || '' ;
2522 if ( ! mountPath . endsWith ( '/' ) ) {
2623 mountPath += '/' ;
2724 }
@@ -59,149 +56,152 @@ module.exports = function(config, allowInsecureHTTP) {
5956 app . enable ( 'trust proxy' ) ;
6057 }
6158
62- const users = config . users ;
63- const useEncryptedPasswords = config . useEncryptedPasswords ? true : false ;
64- const authInstance = new Authentication ( users , useEncryptedPasswords ) ;
65- authInstance . initialize ( app ) ;
66-
67- // CSRF error handler
68- app . use ( function ( err , req , res , next ) {
69- if ( err . code !== 'EBADCSRFTOKEN' ) return next ( err )
70-
71- // handle CSRF token errors here
72- res . status ( 403 )
73- res . send ( 'form tampered with' )
74- } ) ;
75-
76- // Serve the configuration.
77- app . get ( '/parse-dashboard-config.json' , function ( req , res ) {
78- let response = {
79- apps : config . apps ,
80- newFeaturesInLatestVersion : newFeaturesInLatestVersion ,
81- } ;
82-
83- //Based on advice from Doug Wilson here:
84- //https://github.com/expressjs/express/issues/2518
85- const requestIsLocal =
86- req . connection . remoteAddress === '127.0.0.1' ||
87- req . connection . remoteAddress === '::ffff:127.0.0.1' ||
88- req . connection . remoteAddress === '::1' ;
89- if ( ! requestIsLocal && ! req . secure && ! allowInsecureHTTP ) {
90- //Disallow HTTP requests except on localhost, to prevent the master key from being transmitted in cleartext
91- return res . send ( { success : false , error : 'Parse Dashboard can only be remotely accessed via HTTPS' } ) ;
92- }
59+ // wait for app to mount in order to get mountpath
60+ app . on ( 'mount' , function ( ) {
61+ const mountPath = getMount ( app . mountpath ) ;
62+ const users = config . users ;
63+ const useEncryptedPasswords = config . useEncryptedPasswords ? true : false ;
64+ const authInstance = new Authentication ( users , useEncryptedPasswords , mountPath ) ;
65+ authInstance . initialize ( app ) ;
66+
67+ // CSRF error handler
68+ app . use ( function ( err , req , res , next ) {
69+ if ( err . code !== 'EBADCSRFTOKEN' ) return next ( err )
70+
71+ // handle CSRF token errors here
72+ res . status ( 403 )
73+ res . send ( 'form tampered with' )
74+ } ) ;
9375
94- if ( ! requestIsLocal && ! users ) {
95- //Accessing the dashboard over the internet can only be done with username and password
96- return res . send ( { success : false , error : 'Configure a user to access Parse Dashboard remotely' } ) ;
97- }
76+ // Serve the configuration.
77+ app . get ( '/parse-dashboard-config.json' , function ( req , res ) {
78+ let response = {
79+ apps : config . apps ,
80+ newFeaturesInLatestVersion : newFeaturesInLatestVersion ,
81+ } ;
82+
83+ //Based on advice from Doug Wilson here:
84+ //https://github.com/expressjs/express/issues/2518
85+ const requestIsLocal =
86+ req . connection . remoteAddress === '127.0.0.1' ||
87+ req . connection . remoteAddress === '::ffff:127.0.0.1' ||
88+ req . connection . remoteAddress === '::1' ;
89+ if ( ! requestIsLocal && ! req . secure && ! allowInsecureHTTP ) {
90+ //Disallow HTTP requests except on localhost, to prevent the master key from being transmitted in cleartext
91+ return res . send ( { success : false , error : 'Parse Dashboard can only be remotely accessed via HTTPS' } ) ;
92+ }
9893
99- const authentication = req . user ;
94+ if ( ! requestIsLocal && ! users ) {
95+ //Accessing the dashboard over the internet can only be done with username and password
96+ return res . send ( { success : false , error : 'Configure a user to access Parse Dashboard remotely' } ) ;
97+ }
10098
101- const successfulAuth = authentication && authentication . isAuthenticated ;
102- const appsUserHasAccess = authentication && authentication . appsUserHasAccessTo ;
99+ const authentication = req . user ;
100+
101+ const successfulAuth = authentication && authentication . isAuthenticated ;
102+ const appsUserHasAccess = authentication && authentication . appsUserHasAccessTo ;
103+
104+ if ( successfulAuth ) {
105+ if ( appsUserHasAccess ) {
106+ // Restric access to apps defined in user dictionary
107+ // If they didn't supply any app id, user will access all apps
108+ response . apps = response . apps . filter ( function ( app ) {
109+ return appsUserHasAccess . find ( appUserHasAccess => {
110+ return app . appId == appUserHasAccess . appId
111+ } )
112+ } ) ;
113+ }
114+ // They provided correct auth
115+ return res . json ( response ) ;
116+ }
103117
104- if ( successfulAuth ) {
105- if ( appsUserHasAccess ) {
106- // Restric access to apps defined in user dictionary
107- // If they didn't supply any app id, user will access all apps
108- response . apps = response . apps . filter ( function ( app ) {
109- return appsUserHasAccess . find ( appUserHasAccess => {
110- return app . appId == appUserHasAccess . appId
111- } )
112- } ) ;
118+ if ( users ) {
119+ //They provided incorrect auth
120+ return res . sendStatus ( 401 ) ;
113121 }
114- // They provided correct auth
115- return res . json ( response ) ;
116- }
117122
118- if ( users ) {
119- //They provided incorrect auth
120- return res . sendStatus ( 401 ) ;
121- }
123+ //They didn't provide auth, and have configured the dashboard to not need auth
124+ //(ie. didn't supply usernames and passwords)
125+ if ( requestIsLocal ) {
126+ //Allow no-auth access on localhost only, if they have configured the dashboard to not need auth
127+ return res . json ( response ) ;
128+ }
129+ //We shouldn't get here. Fail closed.
130+ res . send ( { success : false , error : 'Something went wrong.' } ) ;
131+ } ) ;
122132
123- //They didn't provide auth, and have configured the dashboard to not need auth
124- //(ie. didn't supply usernames and passwords)
125- if ( requestIsLocal ) {
126- //Allow no-auth access on localhost only, if they have configured the dashboard to not need auth
127- return res . json ( response ) ;
133+ // Serve the app icons. Uses the optional `iconsFolder` parameter as
134+ // directory name, that was setup in the config file.
135+ // We are explicitly not using `__dirpath` here because one may be
136+ // running parse-dashboard from globally installed npm.
137+ if ( config . iconsFolder ) {
138+ try {
139+ var stat = fs . statSync ( config . iconsFolder ) ;
140+ if ( stat . isDirectory ( ) ) {
141+ app . use ( '/appicons' , express . static ( config . iconsFolder ) ) ;
142+ //Check also if the icons really exist
143+ checkIfIconsExistForApps ( config . apps , config . iconsFolder ) ;
144+ }
145+ } catch ( e ) {
146+ // Directory doesn't exist or something.
147+ console . warn ( "Iconsfolder at path: " + config . iconsFolder +
148+ " not found!" ) ;
149+ }
128150 }
129- //We shouldn't get here. Fail closed.
130- res . send ( { success : false , error : 'Something went wrong.' } ) ;
131- } ) ;
132151
133- // Serve the app icons. Uses the optional `iconsFolder` parameter as
134- // directory name, that was setup in the config file.
135- // We are explicitly not using `__dirpath` here because one may be
136- // running parse-dashboard from globally installed npm.
137- if ( config . iconsFolder ) {
138- try {
139- var stat = fs . statSync ( config . iconsFolder ) ;
140- if ( stat . isDirectory ( ) ) {
141- app . use ( '/appicons' , express . static ( config . iconsFolder ) ) ;
142- //Check also if the icons really exist
143- checkIfIconsExistForApps ( config . apps , config . iconsFolder ) ;
152+ app . get ( '/login' , csrf ( ) , function ( req , res ) {
153+ if ( ! users || ( req . user && req . user . isAuthenticated ) ) {
154+ return res . redirect ( `${ mountPath } apps` ) ;
144155 }
145- } catch ( e ) {
146- // Directory doesn't exist or something.
147- console . warn ( "Iconsfolder at path: " + config . iconsFolder +
148- " not found!" ) ;
149- }
150- }
151156
152- app . get ( '/login' , csrf ( ) , function ( req , res ) {
153- if ( ! users || ( req . user && req . user . isAuthenticated ) ) {
154- return res . redirect ( '/apps' ) ;
155- }
156- let mountPath = getMount ( req ) ;
157- let errors = req . flash ( 'error' ) ;
158- if ( errors && errors . length ) {
159- errors = `<div id="login_errors" style="display: none;">
160- ${ errors . join ( ' ' ) }
161- </div>`
162- }
163- res . send ( `<!DOCTYPE html>
164- <head>
165- <link rel="shortcut icon" type="image/x-icon" href="${ mountPath } favicon.ico" />
166- <base href="${ mountPath } "/>
167- <script>
168- PARSE_DASHBOARD_PATH = "${ mountPath } ";
169- </script>
170- </head>
171- <html>
172- <title>Parse Dashboard</title>
173- <body>
174- <div id="login_mount"></div>
175- ${ errors }
176- <script id="csrf" type="application/json">"${ req . csrfToken ( ) } "</script>
177- <script src="${ mountPath } bundles/login.bundle.js"></script>
178- </body>
179- </html>
180- ` ) ;
181- } ) ;
157+ let errors = req . flash ( 'error' ) ;
158+ if ( errors && errors . length ) {
159+ errors = `<div id="login_errors" style="display: none;">
160+ ${ errors . join ( ' ' ) }
161+ </div>`
162+ }
163+ res . send ( `<!DOCTYPE html>
164+ <head>
165+ <link rel="shortcut icon" type="image/x-icon" href="${ mountPath } favicon.ico" />
166+ <base href="${ mountPath } "/>
167+ <script>
168+ PARSE_DASHBOARD_PATH = "${ mountPath } ";
169+ </script>
170+ </head>
171+ <html>
172+ <title>Parse Dashboard</title>
173+ <body>
174+ <div id="login_mount"></div>
175+ ${ errors }
176+ <script id="csrf" type="application/json">"${ req . csrfToken ( ) } "</script>
177+ <script src="${ mountPath } bundles/login.bundle.js"></script>
178+ </body>
179+ </html>
180+ ` ) ;
181+ } ) ;
182182
183- // For every other request, go to index.html. Let client-side handle the rest.
184- app . get ( '/*' , function ( req , res ) {
185- if ( users && ( ! req . user || ! req . user . isAuthenticated ) ) {
186- return res . redirect ( '/ login' ) ;
187- }
188- let mountPath = getMount ( req ) ;
189- res . send ( `<!DOCTYPE html >
190- <head >
191- <link rel="shortcut icon" type="image/x-icon" href="${ mountPath } favicon.ico" />
192- <base href=" ${ mountPath } "/ >
193- <script>
194- PARSE_DASHBOARD_PATH = " ${ mountPath } ";
195- </script >
196- </head >
197- <html >
198- <title>Parse Dashboard</title >
199- <body >
200- <div id="browser_mount "></div >
201- <script src=" ${ mountPath } bundles/dashboard.bundle.js"></script >
202- </body >
203- </html>
204- ` ) ;
183+ // For every other request, go to index.html. Let client-side handle the rest.
184+ app . get ( '/*' , function ( req , res ) {
185+ if ( users && ( ! req . user || ! req . user . isAuthenticated ) ) {
186+ return res . redirect ( ` ${ mountPath } login` ) ;
187+ }
188+ res . send ( `<!DOCTYPE html>
189+ <head >
190+ <link rel="shortcut icon" type="image/x-icon" href=" ${ mountPath } favicon.ico" / >
191+ <base href="${ mountPath } " />
192+ <script >
193+ PARSE_DASHBOARD_PATH = " ${ mountPath } ";
194+ </script>
195+ </head >
196+ <html >
197+ <title>Parse Dashboard</title >
198+ <body >
199+ <div id="browser_mount"></div >
200+ <script src=" ${ mountPath } bundles/dashboard.bundle.js "></script >
201+ </body >
202+ </html >
203+ ` ) ;
204+ } ) ;
205205 } ) ;
206206
207207 return app ;
0 commit comments