mirror of
https://github.com/caprover/caprover
synced 2026-09-24 15:45:48 +00:00
new formatting using vscode
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ app.set('view engine', 'ejs');
|
||||
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
|
||||
app.use(logger('dev'));
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({extended: false}));
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: false
|
||||
}));
|
||||
app.use(cookieParser());
|
||||
|
||||
if (CaptainConstants.isDebug) {
|
||||
@@ -97,15 +99,16 @@ app.use(CaptainConstants.netDataRelativePath, function (req, res, next) {
|
||||
if (!res.locals.user) {
|
||||
Logger.e('User not logged in for NetData');
|
||||
res.sendStatus(500);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
});
|
||||
|
||||
app.use(CaptainConstants.netDataRelativePath, function (req, res, next) {
|
||||
|
||||
httpProxy.web(req, res, {target: 'http://' + CaptainConstants.netDataContainerName + ':19999'});
|
||||
httpProxy.web(req, res, {
|
||||
target: 'http://' + CaptainConstants.netDataContainerName + ':19999'
|
||||
});
|
||||
httpProxy.on('error', function (err, req, res) {
|
||||
if (res.locals.errorProxyHandled) {
|
||||
return;
|
||||
@@ -192,4 +195,4 @@ setTimeout(function () {
|
||||
|
||||
}, 1500);
|
||||
|
||||
module.exports = app;
|
||||
module.exports = app;
|
||||
@@ -233,7 +233,7 @@ class AppsDataStore {
|
||||
}
|
||||
|
||||
updateAppDefinitionInDb(appName, instanceCount, envVars, volumes, nodeId, notExposeAsWebApp, forceSsl, ports,
|
||||
appPushWebhook, authenticator, customNginxConfig, preDeployFunction) {
|
||||
appPushWebhook, authenticator, customNginxConfig, preDeployFunction) {
|
||||
const self = this;
|
||||
|
||||
let app;
|
||||
@@ -251,8 +251,8 @@ class AppsDataStore {
|
||||
})
|
||||
.then(function () {
|
||||
|
||||
if (appPushWebhook.repoInfo && appPushWebhook.repoInfo.repo && appPushWebhook.repoInfo.branch
|
||||
&& appPushWebhook.repoInfo.user && appPushWebhook.repoInfo.password) {
|
||||
if (appPushWebhook.repoInfo && appPushWebhook.repoInfo.repo && appPushWebhook.repoInfo.branch &&
|
||||
appPushWebhook.repoInfo.user && appPushWebhook.repoInfo.password) {
|
||||
return authenticator
|
||||
.getAppPushWebhookDatastore({
|
||||
repo: appPushWebhook.repoInfo.repo,
|
||||
|
||||
@@ -302,7 +302,11 @@ class DataStore {
|
||||
}
|
||||
|
||||
registries.push({
|
||||
id, registryUser, registryPasswordEncrypted, registryDomain, registryImagePrefix
|
||||
id,
|
||||
registryUser,
|
||||
registryPasswordEncrypted,
|
||||
registryDomain,
|
||||
registryImagePrefix
|
||||
});
|
||||
|
||||
self.data.set(DOCKER_REGISTRIES, registries);
|
||||
@@ -476,4 +480,4 @@ class DataStore {
|
||||
|
||||
}
|
||||
|
||||
module.exports = DataStore;
|
||||
module.exports = DataStore;
|
||||
@@ -73,13 +73,13 @@ class DockerApi {
|
||||
if (!nodeID) {
|
||||
if (retryCount < 3) {
|
||||
return new Promise(
|
||||
function (resolve) {
|
||||
function (resolve) {
|
||||
|
||||
setTimeout(function () {
|
||||
resolve()
|
||||
}, 3000);
|
||||
setTimeout(function () {
|
||||
resolve()
|
||||
}, 3000);
|
||||
|
||||
})
|
||||
})
|
||||
.then(function () {
|
||||
|
||||
Logger.d('Retrying to get NodeID for ' + serviceName + ' retry count:' + retryCount);
|
||||
@@ -357,8 +357,7 @@ class DockerApi {
|
||||
|
||||
return Promise.race([
|
||||
self.dockerode.getContainer(nameOrId)
|
||||
.wait()
|
||||
,
|
||||
.wait(),
|
||||
new Promise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
resolve();
|
||||
@@ -379,7 +378,9 @@ class DockerApi {
|
||||
Logger.d('Removing ' + nameOrId);
|
||||
|
||||
return self.dockerode.getContainer(nameOrId)
|
||||
.remove({force: true});
|
||||
.remove({
|
||||
force: true
|
||||
});
|
||||
|
||||
})
|
||||
.then(function () {
|
||||
@@ -729,13 +730,13 @@ class DockerApi {
|
||||
|
||||
if (retryCount < 3) {
|
||||
return new Promise(
|
||||
function (resolve) {
|
||||
function (resolve) {
|
||||
|
||||
setTimeout(function () {
|
||||
resolve()
|
||||
}, 3000);
|
||||
setTimeout(function () {
|
||||
resolve()
|
||||
}, 3000);
|
||||
|
||||
})
|
||||
})
|
||||
.then(function () {
|
||||
|
||||
Logger.d('Retrying to get containerId for ' + serviceName + ' retry count:' + retryCount);
|
||||
@@ -1076,7 +1077,7 @@ class DockerApi {
|
||||
* @returns {Promise.<>}
|
||||
*/
|
||||
updateService(serviceName, imageName, volumes, networks, arrayOfEnvKeyAndValue, secrets, authObject, instanceCount,
|
||||
nodeId, namespace, ports, appObject, preDeployFunction) {
|
||||
nodeId, namespace, ports, appObject, preDeployFunction) {
|
||||
const self = this;
|
||||
return self.dockerode
|
||||
.getService(serviceName)
|
||||
@@ -1390,15 +1391,16 @@ class DockerApi {
|
||||
}
|
||||
|
||||
const dockerApiAddressSplited = (EnvVars.CAPTAIN_DOCKER_API || '').split('\:');
|
||||
const connectionParams = dockerApiAddressSplited.length < 2 ?
|
||||
{socketPath: CaptainConstants.dockerSocketPath}
|
||||
:
|
||||
dockerApiAddressSplited.length === 2 ?
|
||||
{host: dockerApiAddressSplited[0], port: Number(dockerApiAddressSplited[1])} :
|
||||
{
|
||||
host: (dockerApiAddressSplited[0] + ':' + dockerApiAddressSplited[1]),
|
||||
port: Number(dockerApiAddressSplited[2])
|
||||
};
|
||||
const connectionParams = dockerApiAddressSplited.length < 2 ? {
|
||||
socketPath: CaptainConstants.dockerSocketPath
|
||||
} :
|
||||
dockerApiAddressSplited.length === 2 ? {
|
||||
host: dockerApiAddressSplited[0],
|
||||
port: Number(dockerApiAddressSplited[1])
|
||||
} : {
|
||||
host: (dockerApiAddressSplited[0] + ':' + dockerApiAddressSplited[1]),
|
||||
port: Number(dockerApiAddressSplited[2])
|
||||
};
|
||||
|
||||
connectionParams.version = 'v1.30';
|
||||
|
||||
|
||||
@@ -161,4 +161,4 @@ module.exports.injectUserUsingCookieDataOnly = function () {
|
||||
next();
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -6,7 +6,9 @@ const Logger = require('../utils/Logger');
|
||||
const multer = require('multer');
|
||||
const fs = require('fs-extra');
|
||||
const TEMP_UPLOAD = 'temp_upload/';
|
||||
const upload = multer({dest: TEMP_UPLOAD});
|
||||
const upload = multer({
|
||||
dest: TEMP_UPLOAD
|
||||
});
|
||||
|
||||
|
||||
router.get('/:appName/', function (req, res, next) {
|
||||
@@ -138,8 +140,7 @@ router.post('/:appName/', upload.single('sourceFile'), function (req, res, next)
|
||||
|
||||
try {
|
||||
fs.removeSync(tarballSourceFilePath);
|
||||
} catch (ignore) {
|
||||
}
|
||||
} catch (ignore) {}
|
||||
});
|
||||
|
||||
|
||||
@@ -179,4 +180,4 @@ router.post('/:appName/', upload.single('sourceFile'), function (req, res, next)
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
@@ -119,10 +119,10 @@ router.get('/', function (req, res, next) {
|
||||
if (repoInfoEncrypted) {
|
||||
promises.push(
|
||||
Authenticator.get(dataStore.getNameSpace())
|
||||
.decodeAppPushWebhookDatastore(repoInfoEncrypted)
|
||||
.then(function (decryptedData) {
|
||||
app.appPushWebhook.repoInfo = decryptedData;
|
||||
}));
|
||||
.decodeAppPushWebhookDatastore(repoInfoEncrypted)
|
||||
.then(function (decryptedData) {
|
||||
app.appPushWebhook.repoInfo = decryptedData;
|
||||
}));
|
||||
} else {
|
||||
app.appPushWebhook.repoInfo = {};
|
||||
}
|
||||
@@ -325,7 +325,7 @@ router.post('/register/', function (req, res, next) {
|
||||
})
|
||||
.then(function () {
|
||||
|
||||
return serviceManager.createImage(appName, {/*use default dockerfile*/});
|
||||
return serviceManager.createImage(appName, { /*use default dockerfile*/ });
|
||||
|
||||
})
|
||||
.then(function (version) {
|
||||
@@ -460,4 +460,4 @@ router.post('/update/', function (req, res, next) {
|
||||
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
@@ -40,4 +40,4 @@ router.post('/', function (req, res, next) {
|
||||
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
@@ -143,4 +143,4 @@ router.post('/setpush/', function (req, res, next) {
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
@@ -577,4 +577,4 @@ router.post('/nodes/', function (req, res, next) {
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
@@ -104,4 +104,4 @@ router.use('/appDefinitions/', AppDefinitionRouter);
|
||||
|
||||
router.use('/appData/', AppDataRouter);
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
@@ -8,7 +8,9 @@ const ApiStatusCodes = require('../api/ApiStatusCodes');
|
||||
const Logger = require('../utils/Logger');
|
||||
const CaptainConstants = require('../utils/CaptainConstants');
|
||||
|
||||
const urlencodedParser = bodyParser.urlencoded({extended: true});
|
||||
const urlencodedParser = bodyParser.urlencoded({
|
||||
extended: true
|
||||
});
|
||||
|
||||
router.post('/triggerbuild', urlencodedParser, function (req, res, next) {
|
||||
|
||||
@@ -99,4 +101,4 @@ router.post('/triggerbuild', function (req, res, next) {
|
||||
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
@@ -17,7 +17,6 @@ const WEBHOOK_APP_PUSH_SUFFIX = "-webhook-app-push";
|
||||
const WEBHOOK_APP_PUSH_DATASTORE_SUFFIX = "-webhook-app-datastore";
|
||||
|
||||
class Authenticator {
|
||||
|
||||
private encryptionKey: string;
|
||||
private namespace: string;
|
||||
private tokenVersion: string;
|
||||
@@ -31,51 +30,57 @@ class Authenticator {
|
||||
}
|
||||
|
||||
changepass(oldPass: string, newPass: string) {
|
||||
|
||||
const self = this;
|
||||
|
||||
oldPass = oldPass || "";
|
||||
newPass = newPass || "";
|
||||
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
|
||||
.then(function() {
|
||||
if (!oldPass || !newPass || newPass.length < 8) {
|
||||
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Password is too small.");
|
||||
throw ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_ERROR_GENERIC,
|
||||
"Password is too small."
|
||||
);
|
||||
}
|
||||
|
||||
return self.isPasswordCorrect(oldPass);
|
||||
|
||||
})
|
||||
.then(function (isPasswordCorrect) {
|
||||
|
||||
.then(function(isPasswordCorrect) {
|
||||
if (!isPasswordCorrect) {
|
||||
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_WRONG_PASSWORD, "Old password is incorrect.");
|
||||
throw ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_WRONG_PASSWORD,
|
||||
"Old password is incorrect."
|
||||
);
|
||||
}
|
||||
|
||||
self.tokenVersion = uuid();
|
||||
|
||||
const hashed = bcrypt.hashSync(self.encryptionKey + newPass, bcrypt.genSaltSync(10));
|
||||
const hashed = bcrypt.hashSync(
|
||||
self.encryptionKey + newPass,
|
||||
bcrypt.genSaltSync(10)
|
||||
);
|
||||
|
||||
return self.dataStore.setHashedPassword(hashed);
|
||||
});
|
||||
}
|
||||
|
||||
isPasswordCorrect(password: string) {
|
||||
|
||||
const self = this;
|
||||
|
||||
return self.dataStore
|
||||
.getHashedPassword()
|
||||
.then(function (savedHashedPassword) {
|
||||
|
||||
.then(function(savedHashedPassword) {
|
||||
password = password || "";
|
||||
|
||||
if (!savedHashedPassword) {
|
||||
return captainDefaultPassword === password;
|
||||
}
|
||||
|
||||
return bcrypt.compareSync(self.encryptionKey + password, savedHashedPassword);
|
||||
return bcrypt.compareSync(
|
||||
self.encryptionKey + password,
|
||||
savedHashedPassword
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,27 +89,32 @@ class Authenticator {
|
||||
}
|
||||
|
||||
getAuthToken(password: string, keySuffix: string) {
|
||||
|
||||
const self = this;
|
||||
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
.then(function() {
|
||||
return self.isPasswordCorrect(password);
|
||||
})
|
||||
.then(function (isPasswordCorrect) {
|
||||
|
||||
.then(function(isPasswordCorrect) {
|
||||
if (!isPasswordCorrect) {
|
||||
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_WRONG_PASSWORD, "Password is incorrect.");
|
||||
throw ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_WRONG_PASSWORD,
|
||||
"Password is incorrect."
|
||||
);
|
||||
}
|
||||
|
||||
const userObj = {
|
||||
namespace: self.namespace,
|
||||
tokenVersion: self.tokenVersion
|
||||
tokenVersion: self.tokenVersion,
|
||||
};
|
||||
|
||||
return jwt.sign({
|
||||
data: userObj
|
||||
}, self.encryptionKey + (keySuffix ? keySuffix : ""), {expiresIn: "10000h"});
|
||||
return jwt.sign(
|
||||
{
|
||||
data: userObj,
|
||||
},
|
||||
self.encryptionKey + (keySuffix ? keySuffix : ""),
|
||||
{ expiresIn: "10000h" }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -115,39 +125,57 @@ class Authenticator {
|
||||
decodeAuthToken(token: string, keySuffix: string) {
|
||||
const self = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
jwt.verify(
|
||||
token,
|
||||
self.encryptionKey + (keySuffix ? keySuffix : ""),
|
||||
function(err, rawDecoded: any) {
|
||||
if (err) {
|
||||
Logger.d(err);
|
||||
reject(
|
||||
ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID,
|
||||
"Auth token corrupted"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
jwt.verify(token, self.encryptionKey + (keySuffix ? keySuffix : ""), function (err, rawDecoded: any) {
|
||||
if (err) {
|
||||
Logger.d(err);
|
||||
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID, "Auth token corrupted"));
|
||||
return;
|
||||
const decodedData = rawDecoded.data;
|
||||
|
||||
if (decodedData.tokenVersion !== self.tokenVersion) {
|
||||
reject(
|
||||
ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID,
|
||||
"Auth token is not valid anymore. Request for a new auth token"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (decodedData.namespace !== self.namespace) {
|
||||
reject(
|
||||
ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID,
|
||||
"Auth token does not match the namespace"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(decodedData);
|
||||
}
|
||||
|
||||
const decodedData = rawDecoded.data;
|
||||
|
||||
if (decodedData.tokenVersion !== self.tokenVersion) {
|
||||
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID,
|
||||
"Auth token is not valid anymore. Request for a new auth token"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (decodedData.namespace !== self.namespace) {
|
||||
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID,
|
||||
"Auth token does not match the namespace"));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(decodedData);
|
||||
});
|
||||
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getAppPushWebhookDatastore(dataToSave: any) {
|
||||
const self = this;
|
||||
|
||||
return self.getGenericToken(dataToSave, WEBHOOK_APP_PUSH_DATASTORE_SUFFIX);
|
||||
return self.getGenericToken(
|
||||
dataToSave,
|
||||
WEBHOOK_APP_PUSH_DATASTORE_SUFFIX
|
||||
);
|
||||
}
|
||||
|
||||
decodeAppPushWebhookDatastore(token: string) {
|
||||
@@ -160,13 +188,19 @@ class Authenticator {
|
||||
const self = this;
|
||||
|
||||
if (!appName) {
|
||||
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "App name are required for webhook token..");
|
||||
throw ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_ERROR_GENERIC,
|
||||
"App name are required for webhook token.."
|
||||
);
|
||||
}
|
||||
|
||||
return self.getGenericToken({
|
||||
tokenVersion: tokenVersion,
|
||||
appName: appName
|
||||
}, WEBHOOK_APP_PUSH_SUFFIX);
|
||||
return self.getGenericToken(
|
||||
{
|
||||
tokenVersion: tokenVersion,
|
||||
appName: appName,
|
||||
},
|
||||
WEBHOOK_APP_PUSH_SUFFIX
|
||||
);
|
||||
}
|
||||
|
||||
decodeAppPushWebhookToken(token: string) {
|
||||
@@ -176,44 +210,55 @@ class Authenticator {
|
||||
}
|
||||
|
||||
getGenericToken(obj: any, keySuffix: string) {
|
||||
|
||||
const self = this;
|
||||
obj.namespace = self.namespace;
|
||||
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
return jwt.sign({
|
||||
data: obj
|
||||
}, self.encryptionKey + (keySuffix ? keySuffix : ""));
|
||||
});
|
||||
return Promise.resolve().then(function() {
|
||||
return jwt.sign(
|
||||
{
|
||||
data: obj,
|
||||
},
|
||||
self.encryptionKey + (keySuffix ? keySuffix : "")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
decodeGenericToken(token: string, keySuffix: string) {
|
||||
const self = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
jwt.verify(
|
||||
token,
|
||||
self.encryptionKey + (keySuffix ? keySuffix : ""),
|
||||
function(err, rawDecoded: any) {
|
||||
if (err) {
|
||||
Logger.d(err);
|
||||
reject(
|
||||
ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID,
|
||||
"Token corrupted"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
jwt.verify(token, self.encryptionKey + (keySuffix ? keySuffix : ""), function (err, rawDecoded: any) {
|
||||
if (err) {
|
||||
Logger.d(err);
|
||||
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID, "Token corrupted"));
|
||||
return;
|
||||
const decodedData = rawDecoded.data;
|
||||
|
||||
if (decodedData.namespace !== self.namespace) {
|
||||
reject(
|
||||
ApiStatusCodes.createError(
|
||||
ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID,
|
||||
"token does not match the namespace"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(decodedData);
|
||||
}
|
||||
|
||||
const decodedData = rawDecoded.data;
|
||||
|
||||
if (decodedData.namespace !== self.namespace) {
|
||||
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_AUTH_TOKEN_INVALID,
|
||||
"token does not match the namespace"));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(decodedData);
|
||||
});
|
||||
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface IHash {
|
||||
@@ -223,20 +268,22 @@ interface IHash {
|
||||
const authenticatorCache: IHash = {};
|
||||
|
||||
exports = {
|
||||
get: function (namespace: string) {
|
||||
|
||||
get: function(namespace: string): Authenticator | undefined {
|
||||
if (!namespace) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!authenticatorCache[namespace]) {
|
||||
const captainSalt = CaptainManager.get().getCaptainSalt();
|
||||
if (captainSalt) {
|
||||
authenticatorCache[namespace] = new Authenticator(captainSalt, namespace, DataStoreProvider.getDataStore(namespace));
|
||||
authenticatorCache[namespace] = new Authenticator(
|
||||
captainSalt,
|
||||
namespace,
|
||||
DataStoreProvider.getDataStore(namespace)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return authenticatorCache[namespace];
|
||||
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -16,8 +16,8 @@ const DataStoreProvider = require('../datastore/DataStoreProvider');
|
||||
const DEBUG_SALT = 'THIS IS NOT A REAL CERTIFICATE';
|
||||
|
||||
const MAX_FAIL_ALLOWED = 4;
|
||||
const HEALTH_CHECK_INTERVAL = 20000;//ms
|
||||
const TIMEOUT_HEALTH_CHECK = 15000;//ms
|
||||
const HEALTH_CHECK_INTERVAL = 20000; //ms
|
||||
const TIMEOUT_HEALTH_CHECK = 15000; //ms
|
||||
|
||||
class CaptainManager {
|
||||
|
||||
@@ -394,12 +394,16 @@ class CaptainManager {
|
||||
}
|
||||
|
||||
checkCaptainHealth(function (success) {
|
||||
checksPerformed.captainHealth = {value: success};
|
||||
checksPerformed.captainHealth = {
|
||||
value: success
|
||||
};
|
||||
scheduleIfNecessary();
|
||||
});
|
||||
|
||||
checkNginxHealth(function (success) {
|
||||
checksPerformed.nginxHealth = {value: success};
|
||||
checksPerformed.nginxHealth = {
|
||||
value: success
|
||||
};
|
||||
scheduleIfNecessary();
|
||||
});
|
||||
}
|
||||
@@ -493,8 +497,7 @@ class CaptainManager {
|
||||
.then(function () {
|
||||
|
||||
if (netDataInfo.isEnabled) {
|
||||
let vols = [
|
||||
{
|
||||
let vols = [{
|
||||
hostPath: '/proc',
|
||||
containerPath: '/host/proc',
|
||||
mode: 'ro'
|
||||
@@ -853,8 +856,8 @@ class CaptainManager {
|
||||
})
|
||||
.then(function () {
|
||||
|
||||
return fs.outputFile(CaptainConstants.captainStaticFilesDir + CaptainConstants.nginxDomainSpecificHtmlDir
|
||||
+ '/' + domainName + captainConfirmationPath, randomUuid);
|
||||
return fs.outputFile(CaptainConstants.captainStaticFilesDir + CaptainConstants.nginxDomainSpecificHtmlDir +
|
||||
'/' + domainName + captainConfirmationPath, randomUuid);
|
||||
|
||||
})
|
||||
.then(function () {
|
||||
@@ -986,4 +989,4 @@ const captainManagerInstance = new CaptainManager();
|
||||
|
||||
module.exports.get = function () {
|
||||
return captainManagerInstance;
|
||||
};
|
||||
};
|
||||
@@ -6,7 +6,7 @@ const ApiStatusCodes = require('../api/ApiStatusCodes');
|
||||
|
||||
const CAPTAIN_WEBROOT_PATH_CERTBOT = '/captain-webroot';
|
||||
|
||||
const shouldUseStaging = false;//CaptainConstants.isDebug;
|
||||
const shouldUseStaging = false; //CaptainConstants.isDebug;
|
||||
|
||||
|
||||
class CertbotManager {
|
||||
@@ -58,9 +58,9 @@ class CertbotManager {
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
|
||||
const webrootInCaptainContainer = CaptainConstants.captainStaticFilesDir
|
||||
+ CaptainConstants.nginxDomainSpecificHtmlDir
|
||||
+ '/' + domainName;
|
||||
const webrootInCaptainContainer = CaptainConstants.captainStaticFilesDir +
|
||||
CaptainConstants.nginxDomainSpecificHtmlDir +
|
||||
'/' + domainName;
|
||||
|
||||
return fs.ensureDir(webrootInCaptainContainer);
|
||||
|
||||
@@ -69,7 +69,8 @@ class CertbotManager {
|
||||
|
||||
const cmd = ['certbot', 'certonly', '--webroot',
|
||||
'-w', CAPTAIN_WEBROOT_PATH_CERTBOT + '/' + domainName,
|
||||
'-d', domainName, '--non-interactive'];
|
||||
'-d', domainName, '--non-interactive'
|
||||
];
|
||||
|
||||
if (shouldUseStaging) {
|
||||
cmd.push('--staging');
|
||||
@@ -105,9 +106,9 @@ class CertbotManager {
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
|
||||
const rootPathDir = CaptainConstants.letsEncryptEtcPath + '/accounts/acme-'
|
||||
+ (shouldUseStaging ? 'staging' : 'v01')
|
||||
+ '.api.letsencrypt.org/directory';
|
||||
const rootPathDir = CaptainConstants.letsEncryptEtcPath + '/accounts/acme-' +
|
||||
(shouldUseStaging ? 'staging' : 'v01') +
|
||||
'.api.letsencrypt.org/directory';
|
||||
|
||||
if (!fs.existsSync(rootPathDir)) {
|
||||
Logger.d('Fresh install of Certbot. There is no registration directory');
|
||||
@@ -140,7 +141,8 @@ class CertbotManager {
|
||||
|
||||
const cmd = ['certbot', 'register',
|
||||
'--email', emailAddress,
|
||||
'--agree-tos', '--no-eff-email', '--non-interactive'];
|
||||
'--agree-tos', '--no-eff-email', '--non-interactive'
|
||||
];
|
||||
|
||||
if (shouldUseStaging) {
|
||||
cmd.push('--staging');
|
||||
@@ -258,7 +260,7 @@ class CertbotManager {
|
||||
function createCertbotServiceOnNode(nodeId) {
|
||||
|
||||
return dockerApi.createServiceOnNodeId(CaptainConstants.certbotImageName,
|
||||
CaptainConstants.certbotServiceName, null, nodeId)
|
||||
CaptainConstants.certbotServiceName, null, nodeId)
|
||||
.then(function () {
|
||||
|
||||
let waitTimeInMillis = 5000;
|
||||
@@ -340,8 +342,7 @@ class CertbotManager {
|
||||
.then(function () {
|
||||
Logger.d('Updating Certbot service...');
|
||||
|
||||
return dockerApi.updateService(CaptainConstants.certbotServiceName, null, [
|
||||
{
|
||||
return dockerApi.updateService(CaptainConstants.certbotServiceName, null, [{
|
||||
hostPath: CaptainConstants.letsEncryptEtcPath,
|
||||
containerPath: '/etc/letsencrypt'
|
||||
},
|
||||
@@ -370,4 +371,4 @@ class CertbotManager {
|
||||
|
||||
}
|
||||
|
||||
module.exports = CertbotManager;
|
||||
module.exports = CertbotManager;
|
||||
@@ -64,9 +64,9 @@ class DockerRegistry {
|
||||
|
||||
const self = this;
|
||||
|
||||
return CaptainConstants.registrySubDomain + '.'
|
||||
+ self.dataStore.getRootDomain()
|
||||
+ ':' + CaptainConstants.registrySubDomainPort;
|
||||
return CaptainConstants.registrySubDomain + '.' +
|
||||
self.dataStore.getRootDomain() +
|
||||
':' + CaptainConstants.registrySubDomainPort;
|
||||
}
|
||||
|
||||
ensureDockerRegistryRunningOnThisNode() {
|
||||
@@ -84,8 +84,7 @@ class DockerRegistry {
|
||||
protocol: 'tcp',
|
||||
containerPort: 5000,
|
||||
hostPort: CaptainConstants.registrySubDomainPort
|
||||
}], myNodeId, [
|
||||
{
|
||||
}], myNodeId, [{
|
||||
containerPath: '/cert-files',
|
||||
hostPath: CaptainConstants.letsEncryptEtcPath
|
||||
},
|
||||
@@ -243,4 +242,4 @@ class DockerRegistry {
|
||||
|
||||
}
|
||||
|
||||
module.exports = DockerRegistry;
|
||||
module.exports = DockerRegistry;
|
||||
@@ -91,20 +91,22 @@ class LoadBalancerManager {
|
||||
s.keyPath = self.getSslKeyPath(s.publicDomain);
|
||||
}
|
||||
|
||||
s.staticWebRoot = CaptainConstants.nginxStaticRootDir
|
||||
+ CaptainConstants.nginxDomainSpecificHtmlDir + '/'
|
||||
+ s.publicDomain;
|
||||
s.staticWebRoot = CaptainConstants.nginxStaticRootDir +
|
||||
CaptainConstants.nginxDomainSpecificHtmlDir + '/' +
|
||||
s.publicDomain;
|
||||
|
||||
promises.push(
|
||||
Promise.resolve()
|
||||
.then(function () {
|
||||
return ejs.render(s.nginxConfigTemplate, {s: s});
|
||||
})
|
||||
.then(function (rendered) {
|
||||
.then(function () {
|
||||
return ejs.render(s.nginxConfigTemplate, {
|
||||
s: s
|
||||
});
|
||||
})
|
||||
.then(function (rendered) {
|
||||
|
||||
nginxConfigContent += rendered;
|
||||
nginxConfigContent += rendered;
|
||||
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
}
|
||||
@@ -243,18 +245,18 @@ class LoadBalancerManager {
|
||||
domain: captainDomain,
|
||||
serviceExposedPort: CaptainConstants.captainServiceExposedPort,
|
||||
defaultHtmlDir: CaptainConstants.nginxStaticRootDir + CaptainConstants.nginxDefaultHtmlDir,
|
||||
staticWebRoot: CaptainConstants.nginxStaticRootDir
|
||||
+ CaptainConstants.nginxDomainSpecificHtmlDir + '/'
|
||||
+ captainDomain
|
||||
staticWebRoot: CaptainConstants.nginxStaticRootDir +
|
||||
CaptainConstants.nginxDomainSpecificHtmlDir + '/' +
|
||||
captainDomain
|
||||
},
|
||||
registry: {
|
||||
crtPath: self.getSslCertPath(registryDomain),
|
||||
keyPath: self.getSslKeyPath(registryDomain),
|
||||
hasRootSsl: hasRegistrySsl,
|
||||
domain: registryDomain,
|
||||
staticWebRoot: CaptainConstants.nginxStaticRootDir
|
||||
+ CaptainConstants.nginxDomainSpecificHtmlDir + '/'
|
||||
+ registryDomain
|
||||
staticWebRoot: CaptainConstants.nginxStaticRootDir +
|
||||
CaptainConstants.nginxDomainSpecificHtmlDir + '/' +
|
||||
registryDomain
|
||||
}
|
||||
});
|
||||
|
||||
@@ -307,20 +309,20 @@ class LoadBalancerManager {
|
||||
Logger.d('No Captain Nginx service is running. Creating one on captain node...');
|
||||
|
||||
return dockerApi.createServiceOnNodeId(CaptainConstants.nginxImageName, CaptainConstants.nginxServiceName, [{
|
||||
protocol: 'tcp',
|
||||
publishMode: 'host',
|
||||
containerPort: 80,
|
||||
hostPort: CaptainConstants.nginxPortNumber
|
||||
}, {
|
||||
protocol: 'tcp',
|
||||
publishMode: 'host',
|
||||
containerPort: 443,
|
||||
hostPort: 443
|
||||
}], nodeId, null, null, {
|
||||
Reservation: {
|
||||
MemoryBytes: 30 * 1024 * 1024
|
||||
}
|
||||
})
|
||||
protocol: 'tcp',
|
||||
publishMode: 'host',
|
||||
containerPort: 80,
|
||||
hostPort: CaptainConstants.nginxPortNumber
|
||||
}, {
|
||||
protocol: 'tcp',
|
||||
publishMode: 'host',
|
||||
containerPort: 443,
|
||||
hostPort: 443
|
||||
}], nodeId, null, null, {
|
||||
Reservation: {
|
||||
MemoryBytes: 30 * 1024 * 1024
|
||||
}
|
||||
})
|
||||
.then(function () {
|
||||
|
||||
let waitTimeInMillis = 5000;
|
||||
@@ -336,34 +338,38 @@ class LoadBalancerManager {
|
||||
|
||||
return fs
|
||||
.outputFile(
|
||||
CaptainConstants.captainStaticFilesDir
|
||||
+ CaptainConstants.nginxDefaultHtmlDir
|
||||
+ CaptainConstants.captainConfirmationPath,
|
||||
CaptainConstants.captainStaticFilesDir +
|
||||
CaptainConstants.nginxDefaultHtmlDir +
|
||||
CaptainConstants.captainConfirmationPath,
|
||||
self.getCaptainPublicRandomKey())
|
||||
.then(function () {
|
||||
|
||||
return ejs.render(defaultPageTemplate, {message: 'Nothing here yet :/'});
|
||||
return ejs.render(defaultPageTemplate, {
|
||||
message: 'Nothing here yet :/'
|
||||
});
|
||||
|
||||
})
|
||||
.then(function (staticPageContent) {
|
||||
|
||||
return fs.outputFile(
|
||||
CaptainConstants.captainStaticFilesDir +
|
||||
CaptainConstants.nginxDefaultHtmlDir
|
||||
+ '/index.html', staticPageContent);
|
||||
CaptainConstants.nginxDefaultHtmlDir +
|
||||
'/index.html', staticPageContent);
|
||||
|
||||
})
|
||||
.then(function () {
|
||||
|
||||
return ejs.render(defaultPageTemplate, {message: 'An Error Occurred :/'});
|
||||
return ejs.render(defaultPageTemplate, {
|
||||
message: 'An Error Occurred :/'
|
||||
});
|
||||
|
||||
})
|
||||
.then(function (errorPageContent) {
|
||||
|
||||
return fs.outputFile(
|
||||
CaptainConstants.captainStaticFilesDir +
|
||||
CaptainConstants.nginxDefaultHtmlDir
|
||||
+ '/error.html', errorPageContent);
|
||||
CaptainConstants.nginxDefaultHtmlDir +
|
||||
'/error.html', errorPageContent);
|
||||
|
||||
})
|
||||
.then(function () {
|
||||
@@ -440,8 +446,7 @@ class LoadBalancerManager {
|
||||
.then(function () {
|
||||
Logger.d('Updating NGINX service...');
|
||||
|
||||
return dockerApi.updateService(CaptainConstants.nginxServiceName, null, [
|
||||
{
|
||||
return dockerApi.updateService(CaptainConstants.nginxServiceName, null, [{
|
||||
containerPath: CaptainConstants.nginxStaticRootDir,
|
||||
hostPath: CaptainConstants.captainStaticFilesDir
|
||||
},
|
||||
@@ -480,4 +485,4 @@ class LoadBalancerManager {
|
||||
|
||||
}
|
||||
|
||||
module.exports = LoadBalancerManager;
|
||||
module.exports = LoadBalancerManager;
|
||||
@@ -15,8 +15,8 @@ const BUILD_LOG_SIZE = 50;
|
||||
const SOURCE_FOLDER_NAME = 'src';
|
||||
const DOCKER_FILE = 'Dockerfile';
|
||||
const CAPTAIN_DEFINITION_FILE = 'captain-definition';
|
||||
const PLACEHOLDER_DOCKER_FILE_CONTENT = 'FROM ' + CaptainConstants.appPlaceholderImageName
|
||||
+ '\nCMD [ "npm", "start" ]';
|
||||
const PLACEHOLDER_DOCKER_FILE_CONTENT = 'FROM ' + CaptainConstants.appPlaceholderImageName +
|
||||
'\nCMD [ "npm", "start" ]';
|
||||
|
||||
function getRawImageSourceFolder(imageName, newVersionPulled) {
|
||||
return CaptainConstants.captainRawImagesDir + '/' + imageName + '/' + newVersionPulled + '/' + SOURCE_FOLDER_NAME;
|
||||
@@ -241,24 +241,24 @@ class ServiceManager {
|
||||
let directoryInside = null;
|
||||
|
||||
return new Promise(
|
||||
function (resolve, reject) {
|
||||
function (resolve, reject) {
|
||||
|
||||
fs.readdir(rawImageSourceFolder, function (err, files) {
|
||||
fs.readdir(rawImageSourceFolder, function (err, files) {
|
||||
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (files.length !== 1 || !fs.statSync(path.join(rawImageSourceFolder, files[0])).isDirectory()) {
|
||||
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Captain Definition file does not exist!"));
|
||||
return;
|
||||
}
|
||||
if (files.length !== 1 || !fs.statSync(path.join(rawImageSourceFolder, files[0])).isDirectory()) {
|
||||
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Captain Definition file does not exist!"));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(files[0]);
|
||||
resolve(files[0]);
|
||||
|
||||
});
|
||||
})
|
||||
});
|
||||
})
|
||||
.then(function (directory) {
|
||||
|
||||
directoryInside = directory;
|
||||
@@ -461,8 +461,8 @@ class ServiceManager {
|
||||
'Domain name is not accepted. You cannot have two consecutive periods ".." inside a domain name. Please use alphanumerical domains such as myapp.google123.ca');
|
||||
}
|
||||
|
||||
if (customDomain.indexOf(dotRootDomain) >= 0
|
||||
&& (customDomain.indexOf(dotRootDomain) + dotRootDomain.length) === customDomain.length) {
|
||||
if (customDomain.indexOf(dotRootDomain) >= 0 &&
|
||||
(customDomain.indexOf(dotRootDomain) + dotRootDomain.length) === customDomain.length) {
|
||||
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME,
|
||||
'Domain name is not accepted. Custom domain cannot be subdomain of root domain.');
|
||||
}
|
||||
@@ -1002,4 +1002,4 @@ class ServiceManager {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ServiceManager;
|
||||
module.exports = ServiceManager;
|
||||
@@ -80,8 +80,7 @@ class TemplateHelper {
|
||||
|
||||
constructor() {
|
||||
|
||||
const templates = [
|
||||
{
|
||||
const templates = [{
|
||||
templateName: 'node',
|
||||
dockerHubImageName: 'library/node',
|
||||
dockerFileFromName: 'node',
|
||||
@@ -228,4 +227,4 @@ module.exports = {
|
||||
get: function () {
|
||||
return templateHelperInstance;
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -123,7 +123,9 @@ let data = {
|
||||
|
||||
};
|
||||
|
||||
let overridingValues = fs.readJsonSync(CONSTANT_FILE_OVERRIDE, {throws: false});
|
||||
let overridingValues = fs.readJsonSync(CONSTANT_FILE_OVERRIDE, {
|
||||
throws: false
|
||||
});
|
||||
|
||||
if (!!overridingValues) {
|
||||
|
||||
@@ -153,4 +155,4 @@ if (data.isDebug) {
|
||||
data.nginxPortNumber = 80;
|
||||
}
|
||||
|
||||
module.exports = data;
|
||||
module.exports = data;
|
||||
@@ -85,20 +85,26 @@ function startServerOnPort_80_443_3000() {
|
||||
.then(function () {
|
||||
|
||||
http.createServer(function (req, res) {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
res.write(FIREWALL_PASSED);
|
||||
res.end();
|
||||
}).listen(80);
|
||||
|
||||
http.createServer(function (req, res) {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
res.write(FIREWALL_PASSED);
|
||||
res.end();
|
||||
}).listen(443);
|
||||
|
||||
|
||||
http.createServer(function (req, res) {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
res.write(FIREWALL_PASSED);
|
||||
res.end();
|
||||
}).listen(3000);
|
||||
@@ -248,12 +254,10 @@ module.exports.install = function () {
|
||||
})
|
||||
.then(function (nodeId) {
|
||||
|
||||
let volumeToMount = [
|
||||
{
|
||||
hostPath: CaptainConstants.captainRootDirectory,
|
||||
containerPath: CaptainConstants.captainRootDirectory
|
||||
}
|
||||
];
|
||||
let volumeToMount = [{
|
||||
hostPath: CaptainConstants.captainRootDirectory,
|
||||
containerPath: CaptainConstants.captainRootDirectory
|
||||
}];
|
||||
|
||||
let env = [];
|
||||
env.push({
|
||||
@@ -326,6 +330,4 @@ module.exports.install = function () {
|
||||
.then(function () {
|
||||
process.exit();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
@@ -1,21 +1,20 @@
|
||||
module.exports =
|
||||
{
|
||||
keys: {
|
||||
CAPTAIN_DOCKER_API: 'CAPTAIN_DOCKER_API',
|
||||
CAPTAIN_IS_DEBUG: 'CAPTAIN_IS_DEBUG',
|
||||
DEFAULT_PASSWORD: 'DEFAULT_PASSWORD',
|
||||
IS_CAPTAIN_INSTANCE: 'IS_CAPTAIN_INSTANCE'
|
||||
},
|
||||
module.exports = {
|
||||
keys: {
|
||||
CAPTAIN_DOCKER_API: 'CAPTAIN_DOCKER_API',
|
||||
CAPTAIN_IS_DEBUG: 'CAPTAIN_IS_DEBUG',
|
||||
DEFAULT_PASSWORD: 'DEFAULT_PASSWORD',
|
||||
IS_CAPTAIN_INSTANCE: 'IS_CAPTAIN_INSTANCE'
|
||||
},
|
||||
|
||||
BY_PASS_PROXY_CHECK: process.env.BY_PASS_PROXY_CHECK,
|
||||
BY_PASS_PROXY_CHECK: process.env.BY_PASS_PROXY_CHECK,
|
||||
|
||||
CAPTAIN_DOCKER_API: process.env.CAPTAIN_DOCKER_API,
|
||||
CAPTAIN_DOCKER_API: process.env.CAPTAIN_DOCKER_API,
|
||||
|
||||
CAPTAIN_IS_DEBUG: !!process.env.CAPTAIN_IS_DEBUG,
|
||||
CAPTAIN_IS_DEBUG: !!process.env.CAPTAIN_IS_DEBUG,
|
||||
|
||||
MAIN_NODE_IP_ADDRESS: process.env.MAIN_NODE_IP_ADDRESS,
|
||||
MAIN_NODE_IP_ADDRESS: process.env.MAIN_NODE_IP_ADDRESS,
|
||||
|
||||
IS_CAPTAIN_INSTANCE: process.env.IS_CAPTAIN_INSTANCE,
|
||||
IS_CAPTAIN_INSTANCE: process.env.IS_CAPTAIN_INSTANCE,
|
||||
|
||||
DEFAULT_PASSWORD: process.env.DEFAULT_PASSWORD
|
||||
};
|
||||
DEFAULT_PASSWORD: process.env.DEFAULT_PASSWORD
|
||||
};
|
||||
Reference in New Issue
Block a user