diff --git a/src/apps.js b/src/apps.js index 1bcb28cf2..f3e569fe8 100644 --- a/src/apps.js +++ b/src/apps.js @@ -369,7 +369,7 @@ function purchase(appId, appstoreId, callback) { var url = config.apiServerOrigin() + '/api/v1/users/' + result.userId + '/cloudrons/' + result.cloudronId + '/apps/' + appId; var data = { appstoreId: appstoreId }; - superagent.post(url).send(data).query({ accessToken: result.token }).end(function (error, result) { + superagent.post(url).send(data).query({ accessToken: result.token }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error)); if (result.statusCode === 404) return callback(new AppsError(AppsError.NOT_FOUND)); if (result.statusCode !== 201 && result.statusCode !== 200) return callback(new AppsError(AppsError.EXTERNAL_ERROR, util.format('App purchase failed. %s %j', result.status, result.body))); @@ -395,11 +395,11 @@ function unpurchase(appId, appstoreId, callback) { var url = config.apiServerOrigin() + '/api/v1/users/' + appstoreConfig.userId + '/cloudrons/' + appstoreConfig.cloudronId + '/apps/' + appId; - superagent.get(url).query({ accessToken: appstoreConfig.token }).end(function (error, result) { + superagent.get(url).query({ accessToken: appstoreConfig.token }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error)); if (result.statusCode === 404) return callback(null); // was never purchased - superagent.del(url).query({ accessToken: appstoreConfig.token }).end(function (error, result) { + superagent.del(url).query({ accessToken: appstoreConfig.token }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error)); if (result.statusCode !== 204) return callback(new AppsError(AppsError.EXTERNAL_ERROR, util.format('App unpurchase failed. %s %j', result.status, result.body))); @@ -420,7 +420,7 @@ function downloadManifest(appStoreId, manifest, callback) { debug('downloading manifest from %s', url); - superagent.get(url).end(function (error, result) { + superagent.get(url).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new AppsError(AppsError.EXTERNAL_ERROR, 'Network error downloading manifest:' + error.message)); if (result.statusCode !== 200) return callback(new AppsError(AppsError.BAD_FIELD, util.format('Failed to get app info from store.', result.statusCode, result.text))); diff --git a/src/apptask.js b/src/apptask.js index 7d251b36f..e81825886 100644 --- a/src/apptask.js +++ b/src/apptask.js @@ -37,8 +37,8 @@ var addons = require('./addons.js'), backups = require('./backups.js'), certificates = require('./certificates.js'), clients = require('./clients.js'), - config = require('./config.js'), ClientsError = clients.ClientsError, + config = require('./config.js'), database = require('./database.js'), debug = require('debug')('box:apptask'), docker = require('./docker.js'), @@ -232,6 +232,7 @@ function downloadIcon(app, callback) { superagent .get(iconUrl) .buffer(true) + .timeout(30 * 1000) .end(function (error, res) { if (error && !error.response) return retryCallback(new Error('Network error downloading icon:' + error.message)); if (res.statusCode !== 200) return retryCallback(null); // ignore error. this can also happen for apps installed with cloudron-cli diff --git a/src/backups.js b/src/backups.js index 385d30b42..9b21a6057 100644 --- a/src/backups.js +++ b/src/backups.js @@ -177,7 +177,7 @@ function getRestoreConfig(backupId, callback) { api(backupConfig.provider).getRestoreUrl(backupConfig, configFile, function (error, result) { if (error) return callback(error); - superagent.get(result.url).buffer(true).end(function (error, response) { + superagent.get(result.url).buffer(true).timeout(30 * 1000).end(function (error, response) { if (error && !error.response) return callback(new BackupsError(BackupsError.EXTERNAL_ERROR, error.message)); if (response.statusCode !== 200) return callback(new Error('Invalid response code when getting config.json : ' + response.statusCode)); diff --git a/src/cert/acme.js b/src/cert/acme.js index d740051b4..a30a6230b 100644 --- a/src/cert/acme.js +++ b/src/cert/acme.js @@ -63,8 +63,8 @@ function Acme(options) { } Acme.prototype.getNonce = function (callback) { - superagent.get(this.caOrigin + '/directory', function (error, response) { - if (error) return callback(error); + superagent.get(this.caOrigin + '/directory').timeout(30 * 1000).end(function (error, response) { + if (error && !error.response) return callback(error); if (response.statusCode !== 200) return callback(new Error('Invalid response code when fetching nonce : ' + response.statusCode)); return callback(null, response.headers['Replay-Nonce'.toLowerCase()]); @@ -118,7 +118,7 @@ Acme.prototype.sendSignedRequest = function (url, payload, callback) { signature: signature64 }; - superagent.post(url).set('Content-Type', 'application/x-www-form-urlencoded').send(JSON.stringify(data)).end(function (error, res) { + superagent.post(url).set('Content-Type', 'application/x-www-form-urlencoded').send(JSON.stringify(data)).timeout(30 * 1000).end(function (error, res) { if (error && !error.response) return callback(error); // network errors callback(null, res); @@ -259,7 +259,7 @@ Acme.prototype.waitForChallenge = function (challenge, callback) { async.retry({ times: 10, interval: 5000 }, function (retryCallback) { debug('waitingForChallenge: getting status'); - superagent.get(challenge.uri).end(function (error, result) { + superagent.get(challenge.uri).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) { debug('waitForChallenge: network error getting uri %s', challenge.uri); return retryCallback(new AcmeError(AcmeError.EXTERNAL_ERROR, error.message)); // network error @@ -353,7 +353,7 @@ Acme.prototype.downloadChain = function (linkHeader, callback) { var data = [ ]; res.on('data', function(chunk) { data.push(chunk); }); res.on('end', function () { res.text = Buffer.concat(data); done(); }); - }).end(function (error, result) { + }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new AcmeError(AcmeError.EXTERNAL_ERROR, 'Network error when downloading certificate')); if (result.statusCode !== 200) return callback(new AcmeError(AcmeError.EXTERNAL_ERROR, util.format('Failed to get cert. Expecting 200, got %s %s', result.statusCode, result.text))); @@ -379,7 +379,7 @@ Acme.prototype.downloadCertificate = function (domain, certUrl, callback) { var data = [ ]; res.on('data', function(chunk) { data.push(chunk); }); res.on('end', function () { res.text = Buffer.concat(data); done(); }); - }).end(function (error, result) { + }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new AcmeError(AcmeError.EXTERNAL_ERROR, 'Network error when downloading certificate')); if (result.statusCode === 202) return callback(new AcmeError(AcmeError.INTERNAL_ERROR, 'Retry not implemented yet')); if (result.statusCode !== 200) return callback(new AcmeError(AcmeError.EXTERNAL_ERROR, util.format('Failed to get cert. Expecting 200, got %s %s', result.statusCode, result.text))); diff --git a/src/cloudron.js b/src/cloudron.js index 9b289fe89..91b383c40 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -189,7 +189,7 @@ function setTimeZone(ip, callback) { // { url: 'http://ip-api.com/json/%s', jpath: 'timezone' }, // { url: 'http://geoip.nekudo.com/api/%s', jpath: 'time_zone } - superagent.get('http://ip-api.com/json/' + ip).end(function (error, result) { + superagent.get('http://ip-api.com/json/' + ip).timeout(10 * 1000).end(function (error, result) { if ((error && !error.response) || result.statusCode !== 200) { debug('Failed to get geo location: %s', error.message); return callback(null); @@ -277,6 +277,7 @@ function getBoxAndUserDetails(callback) { superagent .get(config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn()) .query({ token: config.token() }) + .timeout(30 * 1000) .end(function (error, result) { if (error && !error.response) return callback(new CloudronError(CloudronError.EXTERNAL_ERROR, 'Cannot reach appstore')); if (result.statusCode !== 200) return callback(new CloudronError(CloudronError.EXTERNAL_ERROR, util.format('%s %j', result.statusCode, result.body))); @@ -335,7 +336,7 @@ function sendHeartbeat() { if (!config.token()) return; var url = config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/heartbeat'; - superagent.post(url).query({ token: config.token(), version: config.version() }).timeout(10000).end(function (error, result) { + superagent.post(url).query({ token: config.token(), version: config.version() }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) debug('Network error sending heartbeat.', error); else if (result.statusCode !== 200) debug('Server responded to heartbeat with %s %s', result.statusCode, result.text); else debug('Heartbeat sent to %s', url); @@ -556,6 +557,7 @@ function doUpgrade(boxUpdateInfo, callback) { superagent.post(config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/upgrade') .query({ token: config.token() }) .send({ version: boxUpdateInfo.version }) + .timeout(30 * 1000) .end(function (error, result) { if (error && !error.response) return upgradeError(new Error('Network error making upgrade request: ' + error)); if (result.statusCode !== 202) return upgradeError(new Error(util.format('Server not ready to upgrade. statusCode: %s body: %j', result.status, result.body))); @@ -614,7 +616,7 @@ function doUpdate(boxUpdateInfo, callback) { debug('updating box %j', args); - superagent.post(INSTALLER_UPDATE_URL).send(args).end(function (error, result) { + superagent.post(INSTALLER_UPDATE_URL).send(args).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return updateError(error); if (result.statusCode !== 202) return updateError(new Error('Error initiating update: ' + JSON.stringify(result.body))); @@ -720,6 +722,7 @@ function doMigrate(options, callback) { .post(config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/migrate') .query({ token: config.token() }) .send(options) + .timeout(30 * 1000) .end(function (error, result) { if (error && !error.response) return unlock(error); // network error if (result.statusCode === 409) return unlock(new CloudronError(CloudronError.BAD_STATE)); diff --git a/src/developer.js b/src/developer.js index 82ea2151c..b974946c2 100644 --- a/src/developer.js +++ b/src/developer.js @@ -89,7 +89,7 @@ function getNonApprovedApps(callback) { assert.strictEqual(typeof callback, 'function'); var url = config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/apps'; - superagent.get(url).query({ token: config.token(), boxVersion: config.version() }).end(function (error, result) { + superagent.get(url).query({ token: config.token(), boxVersion: config.version() }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new DeveloperError(DeveloperError.EXTERNAL_ERROR, error)); if (result.statusCode === 401 || result.statusCode === 403) { debug('Failed to list apps in development. Appstore token invalid or missing. Returning empty list.', result.body); diff --git a/src/dns/caas.js b/src/dns/caas.js index 708811ac7..ff77beca2 100644 --- a/src/dns/caas.js +++ b/src/dns/caas.js @@ -12,8 +12,7 @@ var assert = require('assert'), debug = require('debug')('box:dns/caas'), SubdomainError = require('../subdomains.js').SubdomainError, superagent = require('superagent'), - util = require('util'), - _ = require('underscore'); + util = require('util'); function add(dnsConfig, zoneName, subdomain, type, values, callback) { assert.strictEqual(typeof dnsConfig, 'object'); @@ -36,6 +35,7 @@ function add(dnsConfig, zoneName, subdomain, type, values, callback) { .post(config.apiServerOrigin() + '/api/v1/domains/' + fqdn) .query({ token: dnsConfig.token }) .send(data) + .timeout(30 * 1000) .end(function (error, result) { if (error && !error.response) return callback(error); if (result.statusCode === 400) return callback(new SubdomainError(SubdomainError.BAD_FIELD, result.body.message)); @@ -60,6 +60,7 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { superagent .get(config.apiServerOrigin() + '/api/v1/domains/' + fqdn) .query({ token: dnsConfig.token, type: type }) + .timeout(30 * 1000) .end(function (error, result) { if (error && !error.response) return callback(error); if (result.statusCode !== 200) return callback(new SubdomainError(SubdomainError.EXTERNAL_ERROR, util.format('%s %j', result.statusCode, result.body))); @@ -98,6 +99,7 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { .del(config.apiServerOrigin() + '/api/v1/domains/' + config.appFqdn(subdomain)) .query({ token: dnsConfig.token }) .send(data) + .timeout(30 * 1000) .end(function (error, result) { if (error && !error.response) return callback(error); if (result.statusCode === 400) return callback(new SubdomainError(SubdomainError.BAD_FIELD, result.body.message)); @@ -119,6 +121,7 @@ function getChangeStatus(dnsConfig, changeId, callback) { superagent .get(config.apiServerOrigin() + '/api/v1/domains/' + config.fqdn() + '/status/' + changeId) .query({ token: dnsConfig.token }) + .timeout(30 * 1000) .end(function (error, result) { if (error && !error.response) return callback(error); if (result.statusCode !== 200) return callback(new SubdomainError(SubdomainError.EXTERNAL_ERROR, util.format('%s %j', result.statusCode, result.body))); diff --git a/src/oauthproxy.js b/src/oauthproxy.js index d644cf1f9..deb793a74 100644 --- a/src/oauthproxy.js +++ b/src/oauthproxy.js @@ -91,6 +91,7 @@ function authenticate(req, res, next) { superagent .post(config.internalAdminOrigin() + '/api/v1/oauth/token') .query(query).send(data) + .timeout(30 * 1000) .end(function (error, result) { if (error && !error.response) { console.error(error); diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index 9be3aee06..5dc3a78e3 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -67,7 +67,9 @@ function activate(req, res, next) { if (config.provider() !== 'caas') return next(new HttpSuccess(201, info)); // Now let the api server know we got activated - superagent.post(config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/setup/done').query({ setupToken: req.query.setupToken }).end(function (error, result) { + superagent.post(config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/setup/done').query({ setupToken: req.query.setupToken }) + .timeout(30 * 1000) + .end(function (error, result) { if (error && !error.response) return next(new HttpError(500, error)); if (result.statusCode === 403) return next(new HttpError(403, 'Invalid token')); if (result.statusCode === 409) return next(new HttpError(409, 'Already setup')); @@ -86,7 +88,9 @@ function setupTokenAuth(req, res, next) { if (typeof req.query.setupToken !== 'string') return next(new HttpError(400, 'no setupToken provided')); - superagent.get(config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/setup/verify').query({ setupToken:req.query.setupToken }).end(function (error, result) { + superagent.get(config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/setup/verify').query({ setupToken:req.query.setupToken }) + .timeout(30 * 1000) + .end(function (error, result) { if (error && !error.response) return next(new HttpError(500, error)); if (result.statusCode === 403) return next(new HttpError(403, 'Invalid token')); if (result.statusCode === 409) return next(new HttpError(409, 'Already setup')); diff --git a/src/settings.js b/src/settings.js index 4a6ec9e43..769b61f4b 100644 --- a/src/settings.js +++ b/src/settings.js @@ -483,7 +483,7 @@ function setAppstoreConfig(appstoreConfig, callback) { domain: config.fqdn() }; - superagent.post(url).send(data).query({ accessToken: appstoreConfig.token }).end(function (error, result) { + superagent.post(url).send(data).query({ accessToken: appstoreConfig.token }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new SettingsError(SettingsError.EXTERNAL_ERROR, error.message)); if (result.statusCode === 401) return callback(new SettingsError(SettingsError.EXTERNAL_ERROR, 'invalid appstore token')); if (result.statusCode !== 201) return callback(new SettingsError(SettingsError.EXTERNAL_ERROR, 'unable to register cloudron')); @@ -498,7 +498,7 @@ function setAppstoreConfig(appstoreConfig, callback) { // verify that cloudron belongs to this user const url = config.apiServerOrigin() + '/api/v1/users/' + appstoreConfig.userId + '/cloudrons/' + oldConfig.cloudronId; - superagent.get(url).query({ accessToken: appstoreConfig.token }).end(function (error, result) { + superagent.get(url).query({ accessToken: appstoreConfig.token }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(new SettingsError(SettingsError.EXTERNAL_ERROR, error.message)); if (result.statusCode === 401) return callback(new SettingsError(SettingsError.EXTERNAL_ERROR, 'invalid appstore token')); if (result.statusCode === 403) return callback(new SettingsError(SettingsError.EXTERNAL_ERROR, 'wrong user')); diff --git a/src/storage/caas.js b/src/storage/caas.js index 918cc2aca..490eb0d6e 100644 --- a/src/storage/caas.js +++ b/src/storage/caas.js @@ -22,7 +22,7 @@ function getBackupCredentials(apiConfig, callback) { assert(apiConfig.token); var url = config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/awscredentials'; - superagent.post(url).query({ token: apiConfig.token }).end(function (error, result) { + superagent.post(url).query({ token: apiConfig.token }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(error); if (result.statusCode !== 201) return callback(new Error(result.text)); if (!result.body || !result.body.credentials) return callback(new Error('Unexpected response')); @@ -47,7 +47,7 @@ function getAllPaged(apiConfig, page, perPage, callback) { assert.strictEqual(typeof callback, 'function'); var url = config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/backups'; - superagent.get(url).query({ token: apiConfig.token }).end(function (error, result) { + superagent.get(url).query({ token: apiConfig.token }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(error); if (result.statusCode !== 200) return callback(new Error(result.text)); if (!result.body || !util.isArray(result.body.backups)) return callback(new Error('Unexpected response')); diff --git a/src/sysinfo/caas.js b/src/sysinfo/caas.js index 1f5b43a73..9bbb29f58 100644 --- a/src/sysinfo/caas.js +++ b/src/sysinfo/caas.js @@ -14,7 +14,7 @@ function getIp(callback) { if (process.env.BOX_ENV === 'test') return callback(null, '127.0.0.1'); - superagent.get('http://169.254.169.254/metadata/v1.json').end(function (error, result) { + superagent.get('http://169.254.169.254/metadata/v1.json').timeout(30 * 1000).end(function (error, result) { if (error || result.statusCode !== 200) { console.error('Error getting metadata', error); return callback(new SysInfoError(SysInfoError.INTERNAL_ERROR, 'No IP found')); diff --git a/src/sysinfo/ec2.js b/src/sysinfo/ec2.js index fd1094b1d..c0ff9ab91 100644 --- a/src/sysinfo/ec2.js +++ b/src/sysinfo/ec2.js @@ -12,7 +12,7 @@ var assert = require('assert'), function getIp(callback) { assert.strictEqual(typeof callback, 'function'); - superagent.get('http://169.254.169.254/latest/meta-data/public-ipv4').end(function (error, result) { + superagent.get('http://169.254.169.254/latest/meta-data/public-ipv4').timeout(30 * 1000).end(function (error, result) { if (error) return callback(new SysInfoError(SysInfoError.INTERNAL_ERROR, error.status ? 'Request failed: ' + error.status : 'Network failure')); if (result.statusCode !== 200) return callback(new SysInfoError(SysInfoError.EXTERNAL_ERROR, util.format('%s %j', result.status, result.body))); diff --git a/src/webhooks.js b/src/webhooks.js index 10afafaa3..afb465f8d 100644 --- a/src/webhooks.js +++ b/src/webhooks.js @@ -1,5 +1,3 @@ -/* jslint node:true */ - 'use strict'; exports = module.exports = { @@ -31,7 +29,7 @@ function backupDone(filename, app, appBackupIds, callback) { appBackupIds: appBackupIds }; - superagent.post(url).send(data).query({ token: config.token() }).end(function (error, result) { + superagent.post(url).send(data).query({ token: config.token() }).timeout(30 * 1000).end(function (error, result) { if (error && !error.response) return callback(error); if (result.statusCode !== 200) return callback(new Error(result.text)); if (!result.body) return callback(new Error('Unexpected response'));