Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / useragent / lib / update.js
1 'use strict';
2
3 /**
4  * Build in Native modules.
5  */
6 var path = require('path')
7   , fs = require('fs')
8   , vm = require('vm')
9   , tmp = require('tmp');
10
11 /**
12  * Third party modules.
13  */
14 var request = require('request')
15   , yaml = require('yamlparser');
16
17 /**
18  * Update the regexp.js file
19  *
20  * @param {Function} callback Completion callback.
21  * @api public
22  */
23 exports.update = function update(callback) {
24   // Prepend local additions that are missing from the source
25   fs.readFile(exports.before, 'utf8', function reading(err, before) {
26     if (err) return callback(err);
27
28     // Fetch the remote resource as that is frequently updated
29     request(exports.remote, function downloading(err, res, remote) {
30       if (err) return callback(err);
31       if (res.statusCode !== 200) return callback(new Error('Invalid statusCode returned'));
32
33       // Append get some local additions that are missing from the source
34       fs.readFile(exports.after, 'utf8', function reading(err, after) {
35         if (err) return callback(err);
36
37         // Parse the contents
38         exports.parse([ before, remote, after ], function parsing(err, results, source) {
39           callback(err, results);
40
41           if (!source || err) return;
42
43           //
44           // Save to a tmp file to avoid potential concurrency issues.
45           //
46           tmp.file(function (err, tempFilePath) {
47             if (err) return;
48
49             fs.writeFile(tempFilePath, source, function idk(err) {
50               if (err) return
51
52               fs.rename(tempFilePath, exports.output, function(err) {
53
54               });
55             });
56           });
57         });
58       });
59     });
60   });
61 };
62
63 /**
64  * Parse the given sources.
65  *
66  * @param {Array} sources String versions of the source
67  * @param {Function} callback completion callback
68  * @api public
69  */
70 exports.parse = function parse(sources, callback) {
71   var results = {};
72
73   var data = sources.reduce(function parser(memo, data) {
74     // Try to repair some of the odd structures that are in the yaml files
75     // before parsing it so we generate a uniform structure:
76
77     // Normalize the Operating system versions:
78     data = data.replace(/os_v([1-3])_replacement/gim, function replace(match, version) {
79       return 'v'+ version +'_replacement';
80     });
81
82     // Make sure that we are able to parse the yaml string
83     try { data = yaml.eval(data); }
84     catch (e) {
85       callback(e);
86       callback = null;
87       return memo;
88     }
89
90     // merge the data with the memo;
91     Object.keys(data).forEach(function (key) {
92       var results = data[key];
93       memo[key] = memo[key] || [];
94
95       for (var i = 0, l = results.length; i < l; i++) {
96         memo[key].push(results[i]);
97       }
98     });
99
100     return memo;
101   }, {});
102
103   [
104       {
105           resource: 'user_agent_parsers'
106         , replacement: 'family_replacement'
107         , name: 'browser'
108       }
109     , {
110           resource: 'device_parsers'
111         , replacement: 'device_replacement'
112         , name: 'device'
113       }
114     , {
115           resource: 'os_parsers'
116         , replacement: 'os_replacement'
117         , name: 'os'
118       }
119   ].forEach(function parsing(details) {
120     results[details.resource] = results[details.resource] || [];
121
122     var resources = data[details.resource]
123       , name = details.resource.replace('_parsers', '')
124       , resource
125       , parser;
126
127     for (var i = 0, l = resources.length; i < l; i++) {
128       resource = resources[i];
129
130       // We need to JSON stringify the data to properly add slashes escape other
131       // kinds of crap in the RegularExpression. If we don't do thing we get
132       // some illegal token warnings.
133       parser = 'parser = Object.create(null);\n';
134       parser += 'parser[0] = new RegExp('+ JSON.stringify(resource.regex) + ');\n';
135
136       // Check if we have replacement for the parsed family name
137       if (resource[details.replacement]) {
138         parser += 'parser[1] = "'+ resource[details.replacement].replace('"', '\\"') +'";';
139       } else {
140         parser += 'parser[1] = 0;';
141       }
142
143       parser += '\n';
144
145       if (resource.v1_replacement) {
146         parser += 'parser[2] = "'+ resource.v1_replacement.replace('"', '\\"') +'";';
147       } else {
148         parser += 'parser[2] = 0;';
149       }
150
151       parser += '\n';
152
153       if (resource.v2_replacement) {
154         parser += 'parser[3] = "'+ resource.v2_replacement.replace('"', '\\"') +'";';
155       } else {
156         parser += 'parser[3] = 0;';
157       }
158
159       parser += '\n';
160
161       if (resource.v3_replacement) {
162         parser += 'parser[4] = "'+ resource.v3_replacement.replace('"', '\\"') +'";';
163       } else {
164         parser += 'parser[4] = 0;';
165       }
166
167       parser += '\n';
168       parser += 'exports.'+ details.name +'['+ i +'] = parser;';
169       results[details.resource].push(parser);
170     }
171   });
172
173   // Generate a correct format
174   exports.generate(results, callback);
175 };
176
177 /**
178  * Generate the regular expressions file source code.
179  *
180  * @param {Object} results The parsed result of the regexp.yaml.
181  * @param {Function} callback Completion callback
182  * @api public
183  */
184 exports.generate = function generate(results, callback) {
185   var regexps  = [
186       '"use strict";'
187     , exports.LEADER
188     , 'var parser;'
189     , 'exports.browser = Object.create(null);'
190     , results.user_agent_parsers.join('\n')
191     , 'exports.browser.length = '+ results.user_agent_parsers.length +';'
192
193     , 'exports.device = Object.create(null);'
194     , results.device_parsers.join('\n')
195     , 'exports.device.length = '+ results.device_parsers.length +';'
196
197     , 'exports.os = Object.create(null);'
198     , results.os_parsers.join('\n')
199     , 'exports.os.length = '+ results.os_parsers.length +';'
200   ].join('\n\n');
201
202   // Now that we have generated the structure for the RegExps export file we
203   // need to validate that we created a JavaScript compatible file, if we would
204   // write the file without checking it's content we could be breaking the
205   // module.
206   var sandbox = {
207       exports: {} // Emulate a module context, so everything is attached here
208   };
209
210   // Crossing our fingers that it worked
211   try { vm.runInNewContext(regexps, sandbox, 'validating.vm'); }
212   catch (e) { return callback(e, null, regexps); }
213
214   callback(undefined, sandbox.exports, regexps);
215 };
216
217 /**
218  * The location of the ua-parser regexes yaml file.
219  *
220  * @type {String}
221  * @api private
222  */
223 exports.remote = 'https://raw.githubusercontent.com/ua-parser/uap-core/master/regexes.yaml';
224
225 /**
226  * The locations of our local regexes yaml files.
227  *
228  * @type {String}
229  * @api private
230  */
231 exports.before = path.resolve(__dirname, '..', 'static', 'user_agent.before.yaml');
232 exports.after = path.resolve(__dirname, '..', 'static', 'user_agent.after.yaml');
233
234 /**
235  * The the output location for the generated regexps file
236  *
237  * @type {String}
238  * @api private
239  */
240 exports.output = path.resolve(__dirname, '..', 'lib', 'regexps.js');
241
242 /**
243  * The leader that needs to be added so people know they shouldn't touch all the
244  * things.
245  *
246  * @type {String}
247  * @api private
248  */
249 exports.LEADER = fs.readFileSync(path.join(__dirname, 'donotedit'), 'UTF-8');