@@ -75,8 +75,7 @@ function updateRules(settings, tokens) {
7575
7676function updateRedirects ( firebaseRef , settings ) {
7777 return _when . promise ( function ( resolve , reject , notify ) {
78- var redirects = settings . redirects || null ;
79- firebaseRef . child ( 'hosting/path-redirects' ) . child ( settings . firebase ) . set ( redirects , function ( err ) {
78+ firebaseRef . child ( 'hosting/path-redirects' ) . child ( settings . firebase ) . set ( settings . redirects , function ( err ) {
8079 if ( err ) {
8180 console . log ( chalk . red ( 'Settings Error' ) + ' - Incorrectly formatted "redirects" entry in the firebase.json' ) ;
8281 process . exit ( 1 ) ;
@@ -88,8 +87,7 @@ function updateRedirects(firebaseRef, settings) {
8887
8988function updateRewrites ( firebaseRef , settings ) {
9089 return _when . promise ( function ( resolve , reject , notify ) {
91- var rewrites = settings . rewrites || null ;
92- firebaseRef . child ( 'hosting/rewrites' ) . child ( settings . firebase ) . set ( rewrites , function ( err ) {
90+ firebaseRef . child ( 'hosting/rewrites' ) . child ( settings . firebase ) . set ( settings . rewrites , function ( err ) {
9391 if ( err ) {
9492 console . log ( chalk . red ( 'Settings Error' ) + ' - Incorrectly formatted "rewrites" entry in the firebase.json' ) ;
9593 process . exit ( 1 ) ;
@@ -101,8 +99,7 @@ function updateRewrites(firebaseRef, settings) {
10199
102100function updateHeaders ( firebaseRef , settings ) {
103101 return _when . promise ( function ( resolve , reject , notify ) {
104- var headers = settings . headers || null ;
105- firebaseRef . child ( 'hosting/headers' ) . child ( settings . firebase ) . set ( headers , function ( err ) {
102+ firebaseRef . child ( 'hosting/headers' ) . child ( settings . firebase ) . set ( settings . headers , function ( err ) {
106103 if ( err ) {
107104 console . log ( chalk . red ( 'Settings Error' ) + ' - Incorrectly formatted "headers" entry in the firebase.json' ) ;
108105 process . exit ( 1 ) ;
@@ -112,6 +109,122 @@ function updateHeaders(firebaseRef, settings) {
112109 } ) ;
113110}
114111
112+ function validateRedirects ( redirects ) {
113+ var error = null ;
114+ if ( redirects ) {
115+ if ( ! Array . isArray ( redirects ) ) {
116+ error = 'Redirects entry in the firebase.json must be an Array.' ;
117+ } else {
118+ for ( var i = 0 ; i < redirects . length ; i ++ ) {
119+ var redirect = redirects [ i ] ;
120+ if ( typeof redirect !== 'object' ) {
121+ error = 'Redirect rule: ' + JSON . stringify ( redirect ) + ' Must be an object.' ;
122+ } else if ( ! redirect . source || typeof redirect . source !== 'string' || redirect . source . length == 0 ) {
123+ error = 'Redirect rule: ' + JSON . stringify ( redirect ) + ' Must contain a "source" attribute that\'s a non-empty string.' ;
124+ } else if ( ! redirect . destination || typeof redirect . destination !== 'string' || redirect . destination . length == 0 ) {
125+ error = 'Redirect rule: ' + JSON . stringify ( redirect ) + ' Must contain a "destination" attribute that\'s a non-empty string.' ;
126+ } else if ( ! / ^ ( \/ [ ^ \s ] * | h t t p s ? : \/ \/ [ ^ \s ] + ) $ / . test ( redirect . destination ) ) {
127+ error = 'Redirect destination: "' + redirect . destination + '" Must be a remote or absolute url and start with "http", "https", or a "/".' ;
128+ } else if ( redirect . type !== 301 && redirect . type !== 302 ) {
129+ error = 'Redirect rule: ' + JSON . stringify ( redirect ) + ' Must have a redirect "type" that\'s either 301 for a permanent redirect or 302 for a temporary redirect.' ;
130+ } else if ( Object . keys ( redirect ) . length > 3 ) {
131+ error = 'Redirect rule: ' + JSON . stringify ( redirect ) + ' Must not contain any keys other than "source", "destination", or "type".' ;
132+ }
133+ if ( error ) {
134+ break ;
135+ }
136+ }
137+ }
138+ }
139+ if ( error ) {
140+ console . log ( chalk . red ( 'Settings Error' ) + ' - ' + error ) ;
141+ process . exit ( 1 ) ;
142+ }
143+ }
144+
145+ function validateRewrites ( rewrites ) {
146+ var error = null ;
147+ if ( rewrites ) {
148+ if ( ! Array . isArray ( rewrites ) ) {
149+ error = 'Rewrites entry in the firebase.json must be an Array.' ;
150+ } else {
151+ for ( var i = 0 ; i < rewrites . length ; i ++ ) {
152+ var rewrite = rewrites [ i ] ;
153+ if ( typeof rewrite !== 'object' ) {
154+ error = 'Rewrite rule: ' + JSON . stringify ( rewrite ) + ' Must be an object.' ;
155+ } else if ( ! rewrite . source || typeof rewrite . source !== 'string' || rewrite . source . length == 0 ) {
156+ error = 'Rewrite rule: ' + JSON . stringify ( rewrite ) + ' Must contain a "source" attribute that\'s a non-empty string.' ;
157+ } else if ( ! rewrite . destination || typeof rewrite . destination !== 'string' || rewrite . destination . length == 0 ) {
158+ error = 'Rewrite rule: ' + JSON . stringify ( rewrite ) + ' Must contain a "destination" attribute that\'s a non-empty string.' ;
159+ } else if ( ! / ^ \/ [ ^ \s ] * [ ^ \/ \s ] $ / . test ( rewrite . destination ) ) {
160+ error = 'Rewrite destination: "' + rewrite . destination + '" Must be an absolute path to a file that starts with a "/" and does not end in a "/".' ;
161+ } else if ( Object . keys ( rewrite ) . length > 2 ) {
162+ error = 'Rewrite rule: ' + JSON . stringify ( rewrite ) + ' Must not contain any keys other than "source" or "destination".' ;
163+ }
164+ if ( error ) {
165+ break ;
166+ }
167+ }
168+ }
169+ }
170+ if ( error ) {
171+ console . log ( chalk . red ( 'Settings Error' ) + ' - ' + error ) ;
172+ process . exit ( 1 ) ;
173+ }
174+ }
175+
176+ function validateHeaders ( headers ) {
177+ var error = null ,
178+ supportedHeaders = [
179+ 'Access-Control-Allow-Origin' ,
180+ 'Cache-Control'
181+ ] ;
182+ if ( headers ) {
183+ if ( ! Array . isArray ( headers ) ) {
184+ error = 'Headers entry in the firebase.json must be an Array.' ;
185+ } else {
186+ for ( var i = 0 ; i < headers . length ; i ++ ) {
187+ var header = headers [ i ] ;
188+ if ( typeof header !== 'object' ) {
189+ error = 'Header rule: ' + JSON . stringify ( header ) + ' Must be an object.' ;
190+ } else if ( ! header . source || typeof header . source !== 'string' || header . source . length === 0 ) {
191+ error = 'Header rule: ' + JSON . stringify ( header ) + ' Must contain a "source" attribute that\'s a non-empty string.' ;
192+ } else if ( ! header . headers || ! Array . isArray ( header . headers ) ) {
193+ error = 'Header rule: ' + JSON . stringify ( header ) + ' Must contain a "headers" attribute that\'s an array.' ;
194+ } else if ( Object . keys ( header ) . length > 2 ) {
195+ error = 'Header rule: ' + JSON . stringify ( header ) + ' Must not contain any keys other than "source" or "headers".' ;
196+ }
197+ if ( ! error ) {
198+ for ( var j = 0 ; j < header . headers . length ; j ++ ) {
199+ var individualHeader = header . headers [ j ] ;
200+ if ( typeof individualHeader !== 'object' ) {
201+ error = 'Header: ' + JSON . stringify ( individualHeader ) + ' Must be an object' ;
202+ } else if ( ! individualHeader [ 'key' ] || typeof individualHeader [ 'key' ] !== 'string' || individualHeader [ 'key' ] . length === 0 ) {
203+ error = 'Header: ' + JSON . stringify ( individualHeader ) + ' Must contain a "key" field that\'s one of: "' + supportedHeaders . join ( '", "' ) + '"' ;
204+ } else if ( ! individualHeader [ 'value' ] || typeof individualHeader [ 'value' ] !== 'string' || individualHeader [ 'value' ] . length === 0 ) {
205+ error = 'Header: ' + JSON . stringify ( individualHeader ) + ' Must contain a "value" field that\'s a non-empty string.' ;
206+ } else if ( supportedHeaders . indexOf ( individualHeader [ 'key' ] ) < 0 ) {
207+ error = 'Header key: "' + individualHeader [ 'key' ] + '" is not supported. Supported keys are: "' + supportedHeaders . join ( '", "' ) + '"' ;
208+ } else if ( Object . keys ( individualHeader ) . length > 2 ) {
209+ error = 'Header: ' + JSON . stringify ( individualHeader ) + ' Must not contain any keys other than "key" or "value".' ;
210+ }
211+ if ( error ) {
212+ break ;
213+ }
214+ }
215+ }
216+ if ( error ) {
217+ break ;
218+ }
219+ }
220+ }
221+ }
222+ if ( error ) {
223+ console . log ( chalk . red ( 'Settings Error' ) + ' - ' + error ) ;
224+ process . exit ( 1 ) ;
225+ }
226+ }
227+
115228function uploadSite ( settings , directoryRef , argv ) {
116229 return function ( ) {
117230 var bar = null ;
@@ -520,6 +633,13 @@ module.exports = {
520633 process . exit ( 1 ) ;
521634 }
522635
636+ settings . rewrites = settings . rewrites || null ;
637+ validateRewrites ( settings . rewrites ) ;
638+ settings . redirects = settings . redirects || null ;
639+ validateRedirects ( settings . redirects ) ;
640+ settings . headers = settings . headers || null ;
641+ validateHeaders ( settings . headers ) ;
642+
523643 var firebaseRef = new Firebase ( api . realtimeUrl . replace ( / \/ \/ / , '//firebase.' ) ) ;
524644 firebaseRef . auth ( tokens . firebaseToken , function ( error , result ) {
525645 if ( error ) {
0 commit comments