nodebb-plugin-s3-uploads
Advanced tools
Comparing version 0.2.0 to 0.2.1
266
index.js
@@ -10,4 +10,3 @@ var Package = require("./package.json"); | ||
winston = module.parent.require('winston'), | ||
db = module.parent.require('./database'), | ||
templates = module.parent.require('./../public/src/templates'); | ||
db = module.parent.require('./database'); | ||
@@ -22,3 +21,5 @@ | ||
"secretAccessKey": false, | ||
"bucket": process.env.S3_UPLOADS_BUCKET || undefined | ||
"bucket": process.env.S3_UPLOADS_BUCKET || undefined, | ||
"host": process.env.S3_UPLOADS_HOST || undefined, | ||
"path": process.env.S3_UPLOADS_PATH || undefined | ||
}; | ||
@@ -29,6 +30,12 @@ | ||
function fetchSettings(){ | ||
var adminRoute = '/admin/plugins/s3-uploads'; | ||
function fetchSettings(callback){ | ||
db.getObjectFields(Package.name, Object.keys(settings), function(err, newSettings){ | ||
if(err) { | ||
return winston.error(err); | ||
if (err) { | ||
winston.error(err.message); | ||
if (typeof callback === 'function') { | ||
callback(err); | ||
} | ||
return; | ||
} | ||
@@ -59,2 +66,14 @@ | ||
if(!newSettings.host){ | ||
settings.host = process.env.S3_UPLOADS_HOST || ""; | ||
}else{ | ||
settings.host = newSettings.host; | ||
} | ||
if(!newSettings.path){ | ||
settings.path = process.env.S3_UPLOADS_PATH || ""; | ||
}else{ | ||
settings.path = newSettings.path; | ||
} | ||
if(settings.accessKeyId && settings.secretAccessKey){ | ||
@@ -66,2 +85,6 @@ AWS.config.update({ | ||
} | ||
if (typeof callback === 'function') { | ||
callback(); | ||
} | ||
}); | ||
@@ -85,7 +108,6 @@ } | ||
winston.error(err); | ||
winston.error(err.message); | ||
return err; | ||
} | ||
// Delete settings on deactivate: | ||
plugin.activate = function(){ | ||
@@ -95,3 +117,2 @@ fetchSettings(); | ||
// Delete settings on deactivate: | ||
plugin.deactivate = function(){ | ||
@@ -101,6 +122,62 @@ S3Conn = null; | ||
plugin.load = function(){ | ||
fetchSettings(); | ||
plugin.load = function(app, middleware, controllers, callback){ | ||
fetchSettings(function(err) { | ||
if (err) { | ||
return winston.error(err.message); | ||
} | ||
app.get(adminRoute, middleware.admin.buildHeader, renderAdmin); | ||
app.get('/api' + adminRoute, renderAdmin); | ||
app.post('/api' + adminRoute + '/s3settings', s3settings); | ||
app.post('/api' + adminRoute + '/credentials', credentials); | ||
callback(); | ||
}); | ||
}; | ||
function renderAdmin(req, res) { | ||
var data = { | ||
bucket: settings.bucket, | ||
host: settings.host, | ||
path: settings.path, | ||
accessKeyId: (accessKeyIdFromDb && settings.accessKeyId) || '', | ||
secretAccessKey: (accessKeyIdFromDb && settings.secretAccessKey) || '' | ||
}; | ||
res.render('admin/plugins/s3-uploads', data); | ||
} | ||
function s3settings(req, res, next) { | ||
var data = req.body; | ||
var newSettings = { | ||
bucket: data.bucket || '', | ||
host: data.host || '', | ||
path: data.path || '' | ||
}; | ||
saveSettings(newSettings, res, next); | ||
} | ||
function credentials(req, res, next) { | ||
var data = req.body; | ||
var newSettings = { | ||
accessKeyId: data.accessKeyId || '', | ||
secretAccessKey: data.secretAccessKey || '' | ||
}; | ||
saveSettings(newSettings, res, next); | ||
} | ||
function saveSettings(settings, res, next) { | ||
db.setObject(Package.name, settings, function(err) { | ||
if (err) { | ||
return next(makeError(err)); | ||
} | ||
fetchSettings(); | ||
res.json('Saved!'); | ||
}); | ||
} | ||
plugin.handleUpload = function (image, callback) { | ||
@@ -115,11 +192,25 @@ if(!image || !image.path){ | ||
function putObject(err, buffer){ | ||
// Error from FS module: | ||
if(err){ | ||
if(err) { | ||
return callback(makeError(err)); | ||
} | ||
var s3Path; | ||
if (settings.path && 0 < settings.path.length) { | ||
s3Path = settings.path; | ||
if (!s3Path.match(/\/$/)) { | ||
// Add trailing slash | ||
s3Path = s3Path + '/'; | ||
} | ||
} | ||
else { | ||
s3Path = '/'; | ||
} | ||
var s3KeyPath = s3Path.replace(/^\//, ''); // S3 Key Path should not start with slash. | ||
var params = { | ||
Bucket: settings.bucket, | ||
ACL: "public-read", | ||
Key: uuid() + path.extname(image.name), | ||
Key: s3KeyPath + uuid() + path.extname(image.name), | ||
Body: buffer, | ||
@@ -135,95 +226,100 @@ ContentLength: buffer.length, | ||
var s3Host; | ||
if (settings.host && 0 < settings.host.length) { | ||
s3Host = settings.host; | ||
if (!s3Host.match(/\/$/)) { | ||
// Add trailing slash | ||
s3Host = s3Host + '/'; | ||
} | ||
} | ||
else { | ||
s3Host = params.Bucket + ".s3.amazonaws.com/"; | ||
} | ||
callback(null, { | ||
name: image.name, | ||
// Use protocol-less urls so that both HTTP and HTTPS work: | ||
url: "//" + params.Bucket + ".s3.amazonaws.com/" + params.Key | ||
url: "//" + s3Host + params.Key | ||
}); | ||
}); | ||
} | ||
} | ||
}; | ||
plugin.handleFileUpload = function (file, callback) { | ||
if(!file || !file.path){ | ||
winston.error(file); | ||
return callback(makeError("Invalid file data from plugin hook 'filter:uploadFile'")); | ||
} | ||
var admin = plugin.admin = {}; | ||
var adminRoute = "/plugins/s3-uploads"; | ||
fs.readFile(file.path, putObject); | ||
admin.menu = function(headers) { | ||
headers.plugins.push({ | ||
"route": adminRoute, | ||
"icon": 'fa-picture-o', | ||
"name": 'S3 Uploads' | ||
}); | ||
function putObject(err, buffer){ | ||
if(err) { | ||
return callback(makeError(err)); | ||
} | ||
return headers; | ||
} | ||
var s3Path; | ||
if (settings.path && 0 < settings.path.length) { | ||
s3Path = settings.path; | ||
admin.route = function(pluginAdmin, callback) { | ||
fs.readFile(path.join(__dirname, 'public/templates/admin.tpl'), function(err, tpl) { | ||
if(err){ | ||
return callback(makeError(err), pluginAdmin); | ||
if (!s3Path.match(/\/$/)) { | ||
// Add trailing slash | ||
s3Path = s3Path + '/'; | ||
} | ||
} | ||
else { | ||
s3Path = '/'; | ||
} | ||
pluginAdmin.routes.push({ | ||
route: adminRoute, | ||
method: 'get', | ||
options: function(req, res, next){ | ||
next({ | ||
req: req, | ||
res: res, | ||
route: adminRoute, | ||
name: 'S3 Uploads', | ||
content: templates.prepare(tpl.toString()).parse({ | ||
bucket: settings.bucket, | ||
accessKeyId: (accessKeyIdFromDb && settings.accessKeyId) || "", | ||
secretAccessKey: (accessKeyIdFromDb && settings.secretAccessKey) || "" | ||
}) | ||
}); | ||
var s3KeyPath = s3Path.replace(/^\//, ''); // S3 Key Path should not start with slash. | ||
var params = { | ||
Bucket: settings.bucket, | ||
ACL: "public-read", | ||
Key: s3KeyPath + uuid() + path.extname(file.name), | ||
Body: buffer, | ||
ContentLength: buffer.length, | ||
ContentType: mime.lookup(file.name) | ||
}; | ||
S3().putObject(params, function(err){ | ||
if(err){ | ||
return callback(makeError(err)); | ||
} | ||
}); | ||
pluginAdmin.api.push({ | ||
route: adminRoute + "/bucket", | ||
method: 'post', | ||
callback: function(req, res, next){ | ||
var data = req.body; | ||
var newSettings = { | ||
bucket: data.bucket || "" | ||
var s3Host; | ||
if (settings.host && 0 < settings.host.length) { | ||
s3Host = settings.host; | ||
if (!s3Host.match(/\/$/)) { | ||
// Add trailing slash | ||
s3Host = s3Host + '/'; | ||
} | ||
} | ||
else { | ||
s3Host = params.Bucket + ".s3.amazonaws.com/"; | ||
} | ||
db.setObject(Package.name, newSettings, function(err, res){ | ||
if(err){ | ||
winston.error(makeError(err)); | ||
return next({ error: true, message: err.toString() }); | ||
} | ||
fetchSettings(); | ||
return next({ error: false, message: 'Saved!' }); | ||
}); | ||
} | ||
callback(null, { | ||
name: file.name, | ||
// Use protocol-less urls so that both HTTP and HTTPS work: | ||
url: "//" + s3Host + params.Key | ||
}); | ||
}); | ||
} | ||
}; | ||
pluginAdmin.api.push({ | ||
route: adminRoute + "/credentials", | ||
method: 'post', | ||
callback: function(req, res, next){ | ||
var data = req.body; | ||
var newSettings = { | ||
accessKeyId: data.accessKeyId || "", | ||
secretAccessKey: data.secretAccessKey || "" | ||
}; | ||
var admin = plugin.admin = {}; | ||
db.setObject(Package.name, newSettings, function(err, res){ | ||
if(err){ | ||
winston.error(makeError(err)); | ||
return next({ error: true, message: err.toString() }); | ||
} | ||
admin.menu = function(headers, callback) { | ||
headers.plugins.push({ | ||
"route": '/plugins/s3-uploads', | ||
"icon": 'fa-picture-o', | ||
"name": 'S3 Uploads' | ||
}); | ||
fetchSettings(); | ||
return next({ error: false, message: 'Saved!' }); | ||
}); | ||
} | ||
}); | ||
callback(null, headers); | ||
}; | ||
callback(null, pluginAdmin); | ||
}); | ||
} | ||
}(module.exports)); |
{ | ||
"name": "nodebb-plugin-s3-uploads", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "A plugin for NodeBB to take file uploads and store them on S3", | ||
@@ -11,3 +11,3 @@ "main": "index.js", | ||
"type": "git", | ||
"url": "https://github.com/KanoComputing/nodebb-plugin-s3-uploads.git" | ||
"url": "https://github.com/joe1chen/nodebb-plugin-s3-uploads.git" | ||
}, | ||
@@ -23,10 +23,11 @@ "keywords": [ | ||
"contributors": [ | ||
"Barış Soner Uşaklı <barisusakli@gmail.com>" | ||
"Barış Soner Uşaklı <barisusakli@gmail.com>", | ||
"Joseph Chen <joseph.chen@gmail.com>" | ||
], | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/KanoComputing/nodebb-plugin-s3-uploads/issues" | ||
"url": "https://github.com/joe1chen/nodebb-plugin-s3-uploads/issues" | ||
}, | ||
"dependencies": { | ||
"aws-sdk": "~2.0.0-rc9", | ||
"aws-sdk": "^2.0.23", | ||
"uuid": "~1.4.1", | ||
@@ -33,0 +34,0 @@ "mime": "~1.2.11" |
@@ -6,13 +6,18 @@ { | ||
"description": "A plugin that takes file uploads and store them on S3", | ||
"url": "https://github.com/KanoComputing/nodebb-plugin-s3-uploads", | ||
"url": "https://github.com/joe1chen/nodebb-plugin-s3-uploads", | ||
"library": "./index.js", | ||
"staticDirs": ["./public"], | ||
"staticDirs": { | ||
"s3": "public" | ||
}, | ||
"hooks": [ | ||
{ "hook": "action:app.load", "method": "load"}, | ||
{ "hook": "static:app.load", "method": "load"}, | ||
{ "hook": "action:plugin.activate", "method": "activate"}, | ||
{ "hook": "action:plugin.deactivate", "method": "deactivate"}, | ||
{ "hook": "filter:uploadImage", "method": "handleUpload", "callbacked": true, "priority": 6 }, | ||
{ "hook": "filter:admin.create_routes", "method": "admin.route", "callbacked": true }, | ||
{ "hook": "filter:admin.header.build", "method": "admin.menu", "callbacked": false } | ||
] | ||
{ "hook": "filter:admin.header.build", "method": "admin.menu"}, | ||
{ "hook": "filter:uploadImage", "method": "handleUpload", "priority": 6 }, | ||
{ "hook": "filter:uploadFile", "method": "handleFileUpload", "priority": 6 } | ||
], | ||
"minver": "0.4.0", | ||
"templates": "./public/templates" | ||
} |
# NodeBB S3 Uploads Plugin | ||
[![Dependency Status](https://david-dm.org/joe1chen/nodebb-plugin-s3-uploads.png)](https://david-dm.org/joe1chen/nodebb-plugin-s3-uploads) | ||
| Dependency | Version Requirement | | ||
@@ -29,4 +32,9 @@ | -------------- |:-----------------------:| | ||
export S3_UPLOADS_BUCKET="zzzz" | ||
export S3_UPLOADS_HOST="host" | ||
export S3_UPLOADS_PATH="path" | ||
``` | ||
**NOTE:** Asset host is optional - If you do not specify an asset host, then the default asset host is `<bucket>.s3.amazonaws.com`. | ||
**NOTE:** Asset path is optional - If you do not specify an asset path, then the default asset path is `/`. | ||
### Instance Meta-data | ||
@@ -50,2 +58,4 @@ | ||
* `bucket` — The S3 bucket to upload into | ||
* `host` - The asset host (optional) | ||
* `path` - The asset path (optional) | ||
* `accessKeyId` — The AWS Access Key Id | ||
@@ -52,0 +62,0 @@ * `secretAccessKey` — The AWS Secret Access Key |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
51072
15
276
69
7
2
+ Addedavailable-typed-arrays@1.0.7(transitive)
+ Addedaws-sdk@2.1692.0(transitive)
+ Addedbase64-js@1.5.1(transitive)
+ Addedbuffer@4.9.2(transitive)
+ Addedcall-bind@1.0.8(transitive)
+ Addedcall-bind-apply-helpers@1.0.1(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.1.1(transitive)
+ Addedevents@1.1.1(transitive)
+ Addedfor-each@0.3.4(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.7(transitive)
+ Addedget-proto@1.0.1(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedieee754@1.1.13(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedis-arguments@1.2.0(transitive)
+ Addedis-callable@1.2.7(transitive)
+ Addedis-generator-function@1.1.0(transitive)
+ Addedis-regex@1.2.1(transitive)
+ Addedis-typed-array@1.1.15(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedjmespath@0.16.0(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addedpossible-typed-array-names@1.1.0(transitive)
+ Addedpunycode@1.3.2(transitive)
+ Addedquerystring@0.2.0(transitive)
+ Addedsafe-regex-test@1.1.0(transitive)
+ Addedsax@1.2.1(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedurl@0.10.3(transitive)
+ Addedutil@0.12.5(transitive)
+ Addeduuid@8.0.0(transitive)
+ Addedwhich-typed-array@1.1.18(transitive)
+ Addedxml2js@0.6.2(transitive)
+ Addedxmlbuilder@11.0.1(transitive)
- Removedaws-sdk@2.0.31(transitive)
- Removedsax@0.4.2(transitive)
- Removedxml2js@0.2.6(transitive)
- Removedxmlbuilder@0.4.2(transitive)
Updatedaws-sdk@^2.0.23