Skip to content

Commit 5753503

Browse files
committed
Add security for unlinkg removed addons
1 parent 871dda3 commit 5753503

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

core/cb.addons/addon.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ var Addon = function(logger, _rootPath) {
4343
// Check addon
4444
var packageJsonFile = path.join(addonDir, "package.json");
4545
if (!fs.existsSync(packageJsonFile)) {
46-
throw new Error("No 'package.json' in this repository");
46+
throw new Error("No 'package.json' in this repository: "+addonDir);
4747
}
4848
this.infos = JSON.parse(fs.readFileSync(packageJsonFile, 'utf8'));
4949
if (!this.isValid()) {
50-
throw new Error("Invalid 'package.json' file");
50+
throw new Error("Invalid 'package.json' file: "+packageJsonFile);
5151
}
5252

5353
return this;
@@ -59,6 +59,13 @@ var Addon = function(logger, _rootPath) {
5959
|| (!this.infos.main && !this.infos.client && !this.infos.client.main));
6060
};
6161

62+
// Test is symlink
63+
this.isSymlink = function() {
64+
return Q.nfcall(fs.lstat, this.root).then(function(stats) {
65+
return stats.isSymbolicLink();
66+
});
67+
};
68+
6269
// Check if an addon is client side
6370
this.isClientside = function() {
6471
return (this.infos.client && this.infos.client.main);
@@ -175,6 +182,11 @@ var Addon = function(logger, _rootPath) {
175182
});
176183
};
177184

185+
// Unlink this addon
186+
this.unlink = function() {
187+
return Q.nfcall(fs.unlink, this.root);
188+
};
189+
178190
// Start the node process
179191
this.start = function(app) {
180192
var that = this;

core/cb.addons/main.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var exec = require('child_process').exec;
1212
var Addon = require("./addon");
1313

1414
function setup(options, imports, register, app) {
15-
var logger = imports.logger.namespace("addons", true);
15+
var logger = imports.logger.namespace("addons", false);
1616
var server = imports.server;
1717
var events = imports.events;
1818
var hooks = imports.hooks;
@@ -38,8 +38,15 @@ function setup(options, imports, register, app) {
3838
};
3939

4040
// Load addons list from a directory return as a map name -> addon
41-
var loadAddonsInfos = function(addonsRoot) {
41+
var loadAddonsInfos = function(addonsRoot, options) {
42+
// Diretcory to explore
4243
addonsRoot = addonsRoot || configAddonsPath;
44+
45+
// Options
46+
options = _.defaults({}, options || {}, {
47+
ignoreError: false
48+
});
49+
4350
return Q.nfcall(fs.readdir, addonsRoot).then(function(dirs) {
4451
return _.reduce(dirs, function(previous, dir) {
4552
return previous.then(function(addons) {
@@ -51,6 +58,25 @@ function setup(options, imports, register, app) {
5158
addon.infos.default = isDefaultAddon(addon);
5259
addons[addon.infos.name] = addon;
5360
return Q(addons);
61+
}, function(err) {
62+
logger.error("error", err);
63+
if (options.ignoreError) {
64+
// When ignoring error
65+
// it will check that the addon is not a symlink
66+
// and unlink invalid ones
67+
logger.error("ignore invalid addon", addonPath);
68+
return addon.isSymlink().then(function(symlink) {
69+
if (symlink) {
70+
logger.error("unlink invalid addon:", addon.root);
71+
return addon.unlink();
72+
}
73+
}).then(function() {
74+
return Q(addons);
75+
}, function() {
76+
return Q(addons);
77+
});
78+
}
79+
return Q.reject(err);
5480
});
5581
});
5682
}, Q({}));
@@ -171,7 +197,9 @@ function setup(options, imports, register, app) {
171197
// Prepare defaults addons
172198
return copyDefaultsAddons().then(function() {
173199
// Load collection of addons
174-
return loadAddonsInfos();
200+
return loadAddonsInfos(null, {
201+
ignoreError: true
202+
});
175203
}).then(runAddonsOperation(function(addon) {
176204
// Install node dependencies
177205
return addon.installDependencies();

0 commit comments

Comments
 (0)