aStream.on('end', function () { var source = chunks.join(''); // NOTE: Watchpoint var msg = null; try { source = UglifyJS.minify(source, { fromString: true, mangle: false, output: { comments: true }, parse: { bare_returns: true } }).code; } catch (aE) { // On any failure default to unminified console.warn([ 'MINIFICATION WARNING (harmony):', ' message: ' + aE.message, ' installName: ' + aScript.installName, ' line: ' + aE.line + ' col: ' + aE.col + ' pos: ' + aE.pos ].join('\n')); // Set up a `Warning` header with Q encoding under RFC2047 msg = [ '199 ' + aReq.headers.host + ' MINIFICATION WARNING (harmony):', ' ' + rfc2047.encode(aE.message.replace(/\xAB/g, '`').replace(/\xBB/g, '`')), ' line: ' + aE.line + ' col: ' + aE.col + ' pos: ' + aE.pos, ].join('\u0020'); // TODO: Watchpoint... *express*/*node* exception thrown with CRLF SPACE spec aRes.set('Warning', msg); } aRes.write(source); aRes.end(); });
aStream.on('end', function () { let source = null; let result = null; let msg = null; if (continuation) { continuation = false; source = chunks.join(''); // NOTE: Watchpoint msg = null; try { result = UglifyJS.minify(source, { parse: { bare_returns: true }, compress: { inline: false }, mangle: { }, output: { comments: true } }); if (result.error) { throw result.error; // Passthrough the error if present to our handler } else if(!result.code) { throw new TypeError('UglifyJS error of `code` being absent'); } else { source = result.code; // Calculate a based representation of the hex sha512sum eTag = '"' + Base62.encode( parseInt('0x' + crypto.createHash('sha512').update(source).digest('hex'), 16)) + ' .min.user.js"'; } } catch (aE) { // On any failure default to unminified console.warn([ 'MINIFICATION WARNING (harmony):', ' message: ' + aE.message, ' installName: ' + aScript.installName, ' line: ' + aE.line + ' col: ' + aE.col + ' pos: ' + aE.pos ].join('\n')); // Set up a `Warning` header with Q encoding under RFC2047 msg = [ '199 ' + aReq.headers.host + ' MINIFICATION WARNING (harmony):', ' ' + rfc2047.encode(aE.message.replace(/\xAB/g, '`').replace(/\xBB/g, '`')), ' line: ' + aE.line + ' col: ' + aE.col + ' pos: ' + aE.pos, ].join('\u0020'); // TODO: Watchpoint... *express*/*node* exception thrown with CRLF SPACE spec aRes.set('Warning', msg); // Reset to unminified last modified date stamp lastModified = moment(aScript.updated) .utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT'; // Reset to convert a based representation of the hex sha512sum eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + ' .user.js"'; } // If already client-side... partial HTTP/1.1 Caching if (aReq.get('if-none-match') === eTag) { // Conditionally send lastModified if (aReq.get('if-modified-since') !== lastModified) { aRes.set('Last-Modified', lastModified); } aRes.status(304).send(); // Not Modified return; } // Send the script aRes.set('Content-Type', 'text/javascript; charset=UTF-8'); aStream.setEncoding('utf8'); // HTTP/1.0 Caching aRes.set('Expires', moment(moment() + maxAge * 1000) .utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT'); // HTTP/1.1 Caching aRes.set('Last-Modified', lastModified); aRes.set('Etag', eTag); aRes.write(source); aRes.end(); // NOTE: Try and force a GC source = null; chunks = null; // Don't count installs on raw source route if (aScript.isLib || aReq.params.type) { return; } // Update the install count ++aScript.installs; ++aScript.installsSinceUpdate; // Resave affected properties aScript.save(function (aErr, aScript) { // WARNING: No error handling at this stage }); } });
exports.getSource(aReq, function (aScript, aStream) { let chunks = []; let updateURL = null; let updateUtf = null; let matches = null; let rAnyLocalMetaUrl = new RegExp('^https?://(?:openuserjs\.org|oujs\.org' + (isDev ? '|localhost:' + (process.env.PORT || 8080) : '') + ')/(?:meta|install|src/scripts)/(.+?)/(.+?)\.meta\.js$'); let hasAlternateLocalUpdateURL = false; let rAnyLocalHost = new RegExp('^(?:openuserjs\.org|oujs\.org' + (isDev ? '|localhost:' + (process.env.PORT || 8080) : '') + ')'); var lastModified = null; var eTag = null; var maxAge = 7 * 60 * 60 * 24; // nth day(s) in seconds var now = null; var continuation = true; if (!aScript) { aNext(); return; } if (process.env.FORCE_BUSY_UPDATEURL_CHECK === 'true') { // `@updateURL` must be exact here for OUJS hosted checks // e.g. no `search`, no `hash` updateURL = findMeta(aScript.meta, 'UserScript.updateURL.0.value'); if (updateURL) { // Check for decoding error try { updateUtf = decodeURIComponent(updateURL); } catch (aE) { aRes.set('Warning', '199 ' + aReq.headers.host + rfc2047.encode(' Invalid @updateURL')); aRes.status(444).send(); // No Response return; } // Validate `author` and `name` (installNameBase) to this scripts meta only let matches = updateUtf.match(rAnyLocalMetaUrl); if (matches) { if (cleanFilename(aScript.author, '').toLowerCase() + '/' + cleanFilename(aScript.name, '') === matches[1].toLowerCase() + '/' + matches[2]) { // Same script } else { hasAlternateLocalUpdateURL = true; } } else { // Allow offsite checks updateURL = URL.parse(updateURL); if (rAnyLocalHost.test(updateURL.host)) { hasAlternateLocalUpdateURL = true; } } } else { if (!aScript.isLib) { // Don't serve the script anywhere in this mode and if absent hasAlternateLocalUpdateURL = true; } } if (hasAlternateLocalUpdateURL) { aRes.set('Warning', '199 ' + aReq.headers.host + rfc2047.encode(' Invalid @updateURL in lockdown')); aRes.status(444).send(); // No Response return; } } // HTTP/1.1 Caching aRes.set('Cache-Control', 'public, max-age=' + maxAge + ', no-cache, no-transform, must-revalidate'); // Only minify for response that doesn't contain `.min.` extension if (!/\.min(\.user)?\.js$/.test(aReq._parsedUrl.pathname) || process.env.DISABLE_SCRIPT_MINIFICATION === 'true') { // lastModified = moment(aScript.updated) .utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT'; // Convert a based representation of the hex sha512sum eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + ' .user.js"'; // If already client-side... HTTP/1.1 Caching if (aReq.get('if-none-match') === eTag || aReq.get('if-modified-since') === lastModified) { aRes.status(304).send(); // Not Modified return; } // aStream.on('error', function (aErr) { // This covers errors during connection in direct view console.error( 'S3 GET (chunking native) ', aErr.code, 'for', aScript.installName + '\n' + JSON.stringify(aErr, null, ' ') + '\n' + aErr.stack ); if (continuation) { continuation = false; // Abort aNext(); // fallthrough } }); aStream.on('data', function (aData) { if (continuation) { chunks.push(aData); } }); aStream.on('end', function () { let source = null; if (continuation) { continuation = false; source = chunks.join(''); // NOTE: Watchpoint // Send the script aRes.set('Content-Type', 'text/javascript; charset=UTF-8'); aStream.setEncoding('utf8'); // HTTP/1.0 Caching aRes.set('Expires', moment(moment() + maxAge * 1000).utc() .format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT'); // HTTP/1.1 Caching aRes.set('Last-modified', lastModified); aRes.set('Etag', eTag); aRes.write(source); aRes.end(); // NOTE: Try and force a GC source = null; chunks = null; // Don't count installs on raw source route if (aScript.isLib || aReq.params.type) { return; } // Update the install count ++aScript.installs; ++aScript.installsSinceUpdate; // Resave affected properties aScript.save(function (aErr, aScript) { // WARNING: No error handling at this stage }); } }); } else { // Wants to try minified // lastModified = moment(mtimeUglifyJS > aScript.updated ? mtimeUglifyJS : aScript.updated) .utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT'; // If already client-side... partial HTTP/1.1 Caching if (isPro && aReq.get('if-modified-since') === lastModified) { aRes.status(304).send(); // Not Modified return; } aStream.on('error', function (aErr) { // This covers errors during connection in direct view console.error( 'S3 GET (chunking minified) ', aErr.code, 'for', aScript.installName + '\n' + JSON.stringify(aErr, null, ' ') + '\n' + aErr.stack ); if (continuation) { continuation = false; // Abort aNext(); // fallthrough } }); aStream.on('data', function (aData) { if (continuation) { chunks.push(aData); } }); aStream.on('end', function () { let source = null; let result = null; let msg = null; if (continuation) { continuation = false; source = chunks.join(''); // NOTE: Watchpoint msg = null; try { result = UglifyJS.minify(source, { parse: { bare_returns: true }, compress: { inline: false }, mangle: { }, output: { comments: true } }); if (result.error) { throw result.error; // Passthrough the error if present to our handler } else if(!result.code) { throw new TypeError('UglifyJS error of `code` being absent'); } else { source = result.code; // Calculate a based representation of the hex sha512sum eTag = '"' + Base62.encode( parseInt('0x' + crypto.createHash('sha512').update(source).digest('hex'), 16)) + ' .min.user.js"'; } } catch (aE) { // On any failure default to unminified console.warn([ 'MINIFICATION WARNING (harmony):', ' message: ' + aE.message, ' installName: ' + aScript.installName, ' line: ' + aE.line + ' col: ' + aE.col + ' pos: ' + aE.pos ].join('\n')); // Set up a `Warning` header with Q encoding under RFC2047 msg = [ '199 ' + aReq.headers.host + ' MINIFICATION WARNING (harmony):', ' ' + rfc2047.encode(aE.message.replace(/\xAB/g, '`').replace(/\xBB/g, '`')), ' line: ' + aE.line + ' col: ' + aE.col + ' pos: ' + aE.pos, ].join('\u0020'); // TODO: Watchpoint... *express*/*node* exception thrown with CRLF SPACE spec aRes.set('Warning', msg); // Reset to unminified last modified date stamp lastModified = moment(aScript.updated) .utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT'; // Reset to convert a based representation of the hex sha512sum eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + ' .user.js"'; } // If already client-side... partial HTTP/1.1 Caching if (aReq.get('if-none-match') === eTag) { // Conditionally send lastModified if (aReq.get('if-modified-since') !== lastModified) { aRes.set('Last-Modified', lastModified); } aRes.status(304).send(); // Not Modified return; } // Send the script aRes.set('Content-Type', 'text/javascript; charset=UTF-8'); aStream.setEncoding('utf8'); // HTTP/1.0 Caching aRes.set('Expires', moment(moment() + maxAge * 1000) .utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT'); // HTTP/1.1 Caching aRes.set('Last-Modified', lastModified); aRes.set('Etag', eTag); aRes.write(source); aRes.end(); // NOTE: Try and force a GC source = null; chunks = null; // Don't count installs on raw source route if (aScript.isLib || aReq.params.type) { return; } // Update the install count ++aScript.installs; ++aScript.installsSinceUpdate; // Resave affected properties aScript.save(function (aErr, aScript) { // WARNING: No error handling at this stage }); } }); } });