mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add node installation from other than public site
This commit is contained in:
parent
e94634544c
commit
ff96773295
@ -44,6 +44,7 @@ module.exports = {
|
||||
user: req.user,
|
||||
module: req.body.module,
|
||||
version: req.body.version,
|
||||
url: req.body.url,
|
||||
req: apiUtils.getRequestLogObject(req)
|
||||
}
|
||||
runtimeAPI.nodes.addModule(opts).then(function(info) {
|
||||
|
@ -75,13 +75,16 @@ RED.palette.editor = (function() {
|
||||
});
|
||||
})
|
||||
}
|
||||
function installNodeModule(id,version,callback) {
|
||||
function installNodeModule(id,version,url,callback) {
|
||||
var requestBody = {
|
||||
module: id
|
||||
};
|
||||
if (version) {
|
||||
requestBody.version = version;
|
||||
}
|
||||
if (url) {
|
||||
requestBody.url = url;
|
||||
}
|
||||
$.ajax({
|
||||
url:"nodes",
|
||||
type: "POST",
|
||||
@ -622,7 +625,7 @@ RED.palette.editor = (function() {
|
||||
if ($(this).hasClass('disabled')) {
|
||||
return;
|
||||
}
|
||||
update(entry,loadedIndex[entry.name].version,container,function(err){});
|
||||
update(entry,loadedIndex[entry.name].version,loadedIndex[entry.name].pkg_url,container,function(err){});
|
||||
})
|
||||
|
||||
|
||||
@ -872,7 +875,7 @@ RED.palette.editor = (function() {
|
||||
|
||||
$('<div id="red-ui-palette-module-install-shade" class="red-ui-palette-module-shade hide"><div class="red-ui-palette-module-shade-status"></div><img src="red/images/spin.svg" class="red-ui-palette-spinner"/></div>').appendTo(installTab);
|
||||
}
|
||||
function update(entry,version,container,done) {
|
||||
function update(entry,version,url,container,done) {
|
||||
if (RED.settings.theme('palette.editable') === false) {
|
||||
done(new Error('Palette not editable'));
|
||||
return;
|
||||
@ -898,7 +901,7 @@ RED.palette.editor = (function() {
|
||||
RED.actions.invoke("core:show-event-log");
|
||||
});
|
||||
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.name+" "+version);
|
||||
installNodeModule(entry.name,version,function(xhr) {
|
||||
installNodeModule(entry.name,version,url,function(xhr) {
|
||||
spinner.remove();
|
||||
if (xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
@ -1023,7 +1026,7 @@ RED.palette.editor = (function() {
|
||||
RED.actions.invoke("core:show-event-log");
|
||||
});
|
||||
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.id+" "+entry.version);
|
||||
installNodeModule(entry.id,entry.version,function(xhr) {
|
||||
installNodeModule(entry.id,entry.version,entry.pkg_url,function(xhr) {
|
||||
spinner.remove();
|
||||
if (xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
|
@ -32,6 +32,7 @@ var paletteEditorEnabled = false;
|
||||
var settings;
|
||||
var moduleRe = /^(@[^/]+?[/])?[^/]+?$/;
|
||||
var slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/;
|
||||
var pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//;
|
||||
|
||||
function init(runtime) {
|
||||
events = runtime.events;
|
||||
@ -76,14 +77,17 @@ function checkExistingModule(module,version) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function installModule(module,version) {
|
||||
function installModule(module,version,url) {
|
||||
activePromise = activePromise.then(() => {
|
||||
//TODO: ensure module is 'safe'
|
||||
return new Promise((resolve,reject) => {
|
||||
var installName = module;
|
||||
var isUpgrade = false;
|
||||
try {
|
||||
if (moduleRe.test(module)) {
|
||||
if (url && pkgurlRe.test(url)) {
|
||||
// Git remote url or Tarball url - check the valid package url
|
||||
installName = url;
|
||||
} else if (moduleRe.test(module)) {
|
||||
// Simple module name - assume it can be npm installed
|
||||
if (version) {
|
||||
installName += "@"+version;
|
||||
|
@ -159,6 +159,7 @@ var api = module.exports = {
|
||||
* @param {User} opts.user - the user calling the api
|
||||
* @param {String} opts.module - the id of the module to install
|
||||
* @param {String} opts.version - (optional) the version of the module to install
|
||||
* @param {String} opts.url - (optional) url to install
|
||||
* @param {Object} opts.req - the request to log (optional)
|
||||
* @return {Promise<ModuleInfo>} - the node module info
|
||||
* @memberof @node-red/runtime_nodes
|
||||
@ -183,20 +184,20 @@ var api = module.exports = {
|
||||
return reject(err);
|
||||
}
|
||||
}
|
||||
runtime.nodes.installModule(opts.module,opts.version).then(function(info) {
|
||||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version}, opts.req);
|
||||
runtime.nodes.installModule(opts.module,opts.version,opts.url).then(function(info) {
|
||||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url}, opts.req);
|
||||
return resolve(info);
|
||||
}).catch(function(err) {
|
||||
if (err.code === 404) {
|
||||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:"not_found"}, opts.req);
|
||||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:"not_found"}, opts.req);
|
||||
// TODO: code/status
|
||||
err.status = 404;
|
||||
} else if (err.code) {
|
||||
err.status = 400;
|
||||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:err.code}, opts.req);
|
||||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code}, opts.req);
|
||||
} else {
|
||||
err.status = 400;
|
||||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:err.code||"unexpected_error",message:err.toString()}, opts.req);
|
||||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code||"unexpected_error",message:err.toString()}, opts.req);
|
||||
}
|
||||
return reject(err);
|
||||
})
|
||||
|
@ -150,10 +150,10 @@ function reportNodeStateChange(info,enabled) {
|
||||
}
|
||||
}
|
||||
|
||||
function installModule(module,version) {
|
||||
function installModule(module,version,url) {
|
||||
var existingModule = registry.getModuleInfo(module);
|
||||
var isUpgrade = !!existingModule;
|
||||
return registry.installModule(module,version).then(function(info) {
|
||||
return registry.installModule(module,version,url).then(function(info) {
|
||||
if (isUpgrade) {
|
||||
events.emit("runtime-event",{id:"node/upgraded",retain:false,payload:{module:module,version:version}});
|
||||
} else {
|
||||
|
@ -227,7 +227,7 @@ describe("api/admin/nodes", function() {
|
||||
});
|
||||
request(app)
|
||||
.post('/nodes')
|
||||
.send({module: 'foo',version:"1.2.3"})
|
||||
.send({module: 'foo',version:"1.2.3",url:"https://example/foo-1.2.3.tgz"})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
@ -238,6 +238,7 @@ describe("api/admin/nodes", function() {
|
||||
res.body.nodes[0].should.have.property("id","123");
|
||||
opts.should.have.property("module","foo");
|
||||
opts.should.have.property("version","1.2.3");
|
||||
opts.should.have.property("url","https://example/foo-1.2.3.tgz");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -256,7 +257,7 @@ describe("api/admin/nodes", function() {
|
||||
});
|
||||
request(app)
|
||||
.post('/nodes')
|
||||
.send({module: 'foo',version:"1.2.3"})
|
||||
.send({module: 'foo',version:"1.2.3",url:"https://example/foo-1.2.3.tgz"})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
|
@ -121,6 +121,17 @@ describe('nodes/registry/installer', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("rejects when update requested to existing version and url", function(done) {
|
||||
sinon.stub(typeRegistry,"getModuleInfo", function() {
|
||||
return {
|
||||
version: "0.1.1"
|
||||
}
|
||||
});
|
||||
installer.installModule("this_wont_exist","0.1.1","https://example/foo-0.1.1.tgz").catch(function(err) {
|
||||
err.code.should.be.eql('module_already_loaded');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("rejects with generic error", function(done) {
|
||||
var res = {
|
||||
code: 1,
|
||||
@ -201,6 +212,29 @@ describe('nodes/registry/installer', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it("succeeds when url is valid node-red module", function(done) {
|
||||
var nodeInfo = {nodes:{module:"foo",types:["a"]}};
|
||||
|
||||
var res = {
|
||||
code: 0,
|
||||
stdout:"",
|
||||
stderr:""
|
||||
}
|
||||
var p = Promise.resolve(res);
|
||||
p.catch((err)=>{});
|
||||
initInstaller(p)
|
||||
|
||||
var addModule = sinon.stub(registry,"addModule",function(md) {
|
||||
return when.resolve(nodeInfo);
|
||||
});
|
||||
|
||||
installer.installModule("this_wont_exist",null,"https://example/foo-0.1.1.tgz").then(function(info) {
|
||||
info.should.eql(nodeInfo);
|
||||
done();
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
describe("uninstalls module", function() {
|
||||
|
Loading…
Reference in New Issue
Block a user