mirror of
https://github.com/Foltik/Shimapan
synced 2024-11-10 23:53:31 -05:00
Redo uploading and tests
This commit is contained in:
parent
58e25e4e2a
commit
15db9a47ba
@ -3,17 +3,44 @@ var mongoose = require('mongoose');
|
||||
var UploadSchema = mongoose.Schema({
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
id: {
|
||||
type: String,
|
||||
unique: true,
|
||||
required: true
|
||||
},
|
||||
|
||||
views: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
uploader: String,
|
||||
uploadKey: String,
|
||||
date: Date,
|
||||
file: Object
|
||||
|
||||
uploader: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
uploaderKey: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
|
||||
date: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
},
|
||||
|
||||
mime: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
file: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Upload', UploadSchema);
|
@ -1,7 +1,6 @@
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
var mongoose = require('mongoose');
|
||||
var User = require('../models/User.js');
|
||||
var Upload = require('../models/Upload.js');
|
||||
var Key = require('../models/Key.js');
|
||||
@ -9,106 +8,62 @@ var Key = require('../models/Key.js');
|
||||
var multer = require('multer');
|
||||
var dest = multer({dest: 'uploads/'});
|
||||
|
||||
function fileNameExists(name) {
|
||||
Upload.count({name: name}, function (err, count) {
|
||||
return count !== 0;
|
||||
});
|
||||
}
|
||||
const requireAuth = require('../util/requireAuth').requireAuth;
|
||||
const wrap = require('../util/wrap.js').wrap;
|
||||
|
||||
function genFileName() {
|
||||
var charset = "abcdefghijklmnopqrstuvwxyz";
|
||||
do {
|
||||
var chars = [];
|
||||
for (var i = 0; i < 6; i++)
|
||||
chars.push(charset.charAt(Math.floor(Math.random() * charset.length)));
|
||||
} while (fileNameExists(chars.join('')));
|
||||
return chars.join('');
|
||||
}
|
||||
|
||||
function updateStats(type, id, size) {
|
||||
if (type === 'session') {
|
||||
User.updateOne({username: id}, {$inc: {uploadCount: 1, uploadSize: size}}, function (err) {
|
||||
if (err) throw err;
|
||||
});
|
||||
} else if (type === 'apikey') {
|
||||
Key.updateOne({key: id}, {$inc: {uploadCount: 1, uploadSize: size}}, function (err) {
|
||||
if (err) throw err;
|
||||
});
|
||||
}
|
||||
}
|
||||
const generatedIdExists = async id =>
|
||||
await Upload.countDocuments({id: id}) === 1;
|
||||
|
||||
var checkApiKey = function (key, cb) {
|
||||
Key.find({key: key}, function (err, res) {
|
||||
if (err) throw err;
|
||||
cb(res.length === 1, res);
|
||||
});
|
||||
const generateId = async () => {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyz";
|
||||
const len = 6;
|
||||
|
||||
const id = [...Array(len)]
|
||||
.map(() => charset.charAt(Math.floor(Math.random() * charset.length)))
|
||||
.join('');
|
||||
|
||||
return await generatedIdExists(id)
|
||||
? generateId()
|
||||
: id;
|
||||
};
|
||||
|
||||
var checkScope = function (type, id, perm, cb) {
|
||||
if (type === 'session') {
|
||||
User.findOne({username: id}, function (err, user) {
|
||||
if (err) throw err;
|
||||
cb(user.scope.indexOf(perm) !== -1);
|
||||
});
|
||||
} else {
|
||||
Key.findOne({key: id}, function (err, key) {
|
||||
if (err) throw err;
|
||||
cb(key.scope.indexOf(perm) !== -1);
|
||||
});
|
||||
}
|
||||
};
|
||||
const updateStats = async req =>
|
||||
Promise.all([
|
||||
User.updateOne({username: req.authUser}, {$inc: {uploadCount: 1, uploadSize: req.file.size}}),
|
||||
req.authKey
|
||||
? Key.updateOne({key: req.authKey}, {$inc: {uploadCount: 1, uploadSize: req.file.size}})
|
||||
: Promise.resolve()
|
||||
]);
|
||||
|
||||
function uploadFile(req, res, type, key) {
|
||||
|
||||
router.post('/', requireAuth('file.upload'), dest.single('file'), wrap(async (req, res, next) => {
|
||||
if (!req.file)
|
||||
return res.status(400).json({'message': 'No file specified.'});
|
||||
return res.status(400).json({message: 'No file specified.'});
|
||||
|
||||
// Size must be below 128 Megabytes (1024*1024*128 Bytes)
|
||||
if (req.file.size >= 134217728)
|
||||
return res.status(413).json({'message': 'File too large.'});
|
||||
// Max file size is 128 MiB
|
||||
if (req.file.size > 1024 * 1024 * 128)
|
||||
return res.status(413).json({message: 'File too large.'});
|
||||
|
||||
var uploader = type === 'session' ? req.session.passport.user : key[0].username;
|
||||
var uploadKey = type === 'apikey' ? key[0].key : null;
|
||||
var id = type === 'session' ? req.session.passport.user : key[0].key;
|
||||
const upload = {
|
||||
name: req.file.originalname,
|
||||
id: await generateId(),
|
||||
uploader: req.authUser,
|
||||
uploaderKey: req.authKey,
|
||||
date: Date.now(),
|
||||
mime: req.file.mimetype,
|
||||
file: req.file
|
||||
};
|
||||
|
||||
checkScope(type, id, 'file.upload', function (valid) {
|
||||
if (!valid)
|
||||
return res.status(403).json({'message': 'No permission.'});
|
||||
await Promise.all([
|
||||
Upload.create(upload),
|
||||
updateStats(req)
|
||||
]);
|
||||
|
||||
var entry = {
|
||||
name: genFileName(),
|
||||
uploader: uploader,
|
||||
uploadKey: uploadKey,
|
||||
date: Date.now(),
|
||||
file: req.file
|
||||
};
|
||||
|
||||
updateStats(type, id, req.file.size);
|
||||
|
||||
Upload.create(entry, function (err) {
|
||||
if (err) throw err;
|
||||
res.status(200).json({
|
||||
name: entry.name,
|
||||
url: 'https://shimapan.rocks/v/' + entry.name
|
||||
});
|
||||
});
|
||||
res.status(200).json({
|
||||
id: upload.id,
|
||||
url: 'https://shimapan.rocks/v/' + upload.id
|
||||
});
|
||||
}
|
||||
|
||||
router.post('/', dest.single('file'), function (req, res) {
|
||||
if (!req.session || !req.session.passport) {
|
||||
if (!req.body.apikey) {
|
||||
return res.sendStatus(401);
|
||||
} else {
|
||||
checkApiKey(req.body.apikey, function (valid, key) {
|
||||
if (!valid)
|
||||
return res.sendStatus(401);
|
||||
else
|
||||
uploadFile(req, res, 'apikey', key);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
uploadFile(req, res, 'session');
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
module.exports = router;
|
||||
|
146
test/api.js
146
test/api.js
@ -1,8 +1,5 @@
|
||||
process.env.NODE_ENV = 'test';
|
||||
|
||||
const app = require('../server');
|
||||
const server = app.server;
|
||||
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-http'));
|
||||
const should = chai.should();
|
||||
@ -14,6 +11,21 @@ const Upload = require('../app/models/Upload.js');
|
||||
const util = require('./testUtil.js');
|
||||
const canonicalize = require('../app/util/canonicalize').canonicalize;
|
||||
|
||||
let app;
|
||||
let server;
|
||||
let agent;
|
||||
|
||||
before(() => {
|
||||
const main = require('../server.js');
|
||||
app = main.app;
|
||||
server = main.server;
|
||||
agent = chai.request.agent(app);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
describe('Users', function() {
|
||||
beforeEach(async () => util.clearDatabase());
|
||||
|
||||
@ -22,7 +34,7 @@ describe('Users', function() {
|
||||
async function verifySuccessfulRegister(user) {
|
||||
await util.createTestInvite();
|
||||
|
||||
const res = await util.registerUser(user);
|
||||
const res = await util.registerUser(user, agent);
|
||||
|
||||
res.should.have.status(200);
|
||||
res.body.should.be.a('object');
|
||||
@ -49,11 +61,11 @@ describe('Users', function() {
|
||||
async function verifyRejectedInvite(invite, message) {
|
||||
const user = {username: 'user', password: 'pass', invite: 'code'};
|
||||
if (invite) {
|
||||
await util.createInvite(invite);
|
||||
await util.createInvite(invite, agent);
|
||||
user.invite = invite.code;
|
||||
}
|
||||
|
||||
const res = await(util.registerUser(user));
|
||||
const res = await(util.registerUser(user, agent));
|
||||
res.should.have.status(422);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('message').eql(message);
|
||||
@ -64,18 +76,18 @@ describe('Users', function() {
|
||||
);
|
||||
|
||||
it('MUST NOT register a used invite', async () =>
|
||||
verifyRejectedInvite({used: new Date()}, 'Invite already used.')
|
||||
verifyRejectedInvite({code: 'code', used: new Date()}, 'Invite already used.')
|
||||
);
|
||||
|
||||
it('MUST NOT register an expired invite', async () =>
|
||||
verifyRejectedInvite({exp: new Date()}, 'Invite expired.')
|
||||
verifyRejectedInvite({code: 'code', exp: new Date()}, 'Invite expired.')
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
describe('2 Invalid Usernames', () => {
|
||||
async function verifyRejectedUsername(user, message) {
|
||||
const res = await util.registerUser(user);
|
||||
const res = await util.registerUser(user, agent);
|
||||
res.should.have.status(422);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('message').eql(message);
|
||||
@ -86,7 +98,7 @@ describe('Users', function() {
|
||||
const user0 = {username: 'user', password: 'pass', invite: 'code0'};
|
||||
const user1 = {username: 'user', password: 'diff', invite: 'code1'};
|
||||
|
||||
await util.registerUser(user0);
|
||||
await util.registerUser(user0, agent);
|
||||
return verifyRejectedUsername(user1, 'Username in use.');
|
||||
});
|
||||
|
||||
@ -95,7 +107,7 @@ describe('Users', function() {
|
||||
const user0 = {username: 'bigbird', password: 'pass', invite: 'code0'};
|
||||
const user1 = {username: 'ᴮᴵᴳᴮᴵᴿᴰ', password: 'diff', invite: 'code1'};
|
||||
|
||||
await util.registerUser(user0);
|
||||
await util.registerUser(user0, agent);
|
||||
return verifyRejectedUsername(user1, 'Username in use.');
|
||||
});
|
||||
|
||||
@ -127,22 +139,17 @@ describe('Users', function() {
|
||||
|
||||
describe('/POST login', () => {
|
||||
async function verifySuccessfulLogin(credentials) {
|
||||
const agent = chai.request.agent(server);
|
||||
|
||||
const res = await util.login(credentials, agent);
|
||||
res.should.have.status(200);
|
||||
res.body.should.have.property('message').equal('Logged in.');
|
||||
res.should.have.cookie('session.id');
|
||||
|
||||
const ping = await util.ping(agent);
|
||||
ping.should.have.status(200);
|
||||
ping.body.should.have.property('message').equal('pong');
|
||||
|
||||
agent.close();
|
||||
const whoami = await util.whoami(agent);
|
||||
whoami.should.have.status(200);
|
||||
}
|
||||
|
||||
async function verifyFailedLogin(credentials) {
|
||||
const res = await util.login(credentials);
|
||||
const res = await util.login(credentials, agent);
|
||||
res.should.have.status(401);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('message').equal('Unauthorized.');
|
||||
@ -150,15 +157,19 @@ describe('Users', function() {
|
||||
|
||||
describe('0 Valid Request', () => {
|
||||
it('SHOULD accept a valid user with a valid password', async () => {
|
||||
await util.createTestUser();
|
||||
await util.createTestUser(agent);
|
||||
return verifySuccessfulLogin({username: 'user', password: 'pass'});
|
||||
});
|
||||
|
||||
it('SHOULD accept any non-normalized variant of a username with a valid password', async () => {
|
||||
await util.create
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
describe('1 Invalid Password', () => {
|
||||
it('SHOULD NOT accept an invalid password', async () => {
|
||||
await util.createTestUser();
|
||||
await util.createTestUser(agent);
|
||||
return verifyFailedLogin({username: 'user', password: 'bogus'});
|
||||
});
|
||||
});
|
||||
@ -171,48 +182,87 @@ describe('Users', function() {
|
||||
});
|
||||
});
|
||||
|
||||
/*describe('Uploads', () => {
|
||||
describe('/POST upload', () => {
|
||||
describe('Uploads', () => {
|
||||
beforeEach(async () => util.clearDatabase());
|
||||
|
||||
describe('/POST upload', () => {
|
||||
async function verifySuccessfulUpload(file) {
|
||||
const res = await util.upload(file, agent);
|
||||
res.should.have.status(200);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('url');
|
||||
res.body.should.have.property('id').match(/^[a-z]{6}$/);
|
||||
}
|
||||
|
||||
async function verifyFailedUpload(file, status, message) {
|
||||
const res = await util.upload(file, agent);
|
||||
res.should.have.status(status);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('message').equal(message);
|
||||
}
|
||||
|
||||
describe('0 Valid Request', () => {
|
||||
it('SHOULD accept logged in valid upload', function(done) {
|
||||
util.verifySuccessfulUpload({
|
||||
username: 'TestUser2',
|
||||
password: 'TestPassword'
|
||||
}, done);
|
||||
it('SHOULD accept logged in valid upload', async () => {
|
||||
await Promise.all([
|
||||
util.createTestSession(agent),
|
||||
util.createTestFile(2048, 'test.bin')
|
||||
]);
|
||||
|
||||
await verifySuccessfulUpload('test.bin');
|
||||
|
||||
return Promise.all([
|
||||
util.logout(agent),
|
||||
util.deleteTestFile('test.bin')
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('1 Invalid Authentication', () => {
|
||||
it('SHOULD NOT accept unauthenticated request', function(done) {
|
||||
util.verifyFailedAuthUpload(done);
|
||||
});
|
||||
});
|
||||
it('SHOULD NOT accept an unauthenticated request', async () =>
|
||||
verifyFailedUpload(null, 401, 'Unauthorized.')
|
||||
);
|
||||
|
||||
describe('2 Invalid Permission', () => {
|
||||
it('SHOULD NOT accept without file.upload permission', function(done) {
|
||||
util.verifyFailedPermissionUpload({
|
||||
username: 'TestUser1',
|
||||
password: 'TestPassword'
|
||||
}, done);
|
||||
it('SHOULD NOT accept a request without file.upload scope', async () => {
|
||||
await util.createInvite({code: 'code', scope: []});
|
||||
await util.registerUser({username: 'user', password: 'pass', invite: 'code'}, agent);
|
||||
await util.login({username: 'user', password: 'pass'}, agent);
|
||||
|
||||
await util.createTestFile(2048, 'test.bin');
|
||||
|
||||
await verifyFailedUpload('test.bin', 403, 'Forbidden.');
|
||||
|
||||
return Promise.all([
|
||||
util.logout(agent),
|
||||
util.deleteTestFile('test.bin')
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('3 Invalid File', () => {
|
||||
it('SHOULD NOT accept invalid size', function(done) {
|
||||
util.verifyFailedSizeUpload({
|
||||
username: 'TestUser2',
|
||||
password: 'TestPassword'
|
||||
}, done);
|
||||
})
|
||||
it('SHOULD NOT accept a too large file', async () => {
|
||||
await Promise.all([
|
||||
util.createTestSession(agent),
|
||||
util.createTestFile(1024 * 1024 * 129, 'large.bin') // 129 MiB, limit is 128 MiB
|
||||
]);
|
||||
|
||||
await verifyFailedUpload('large.bin', 413, 'File too large.');
|
||||
|
||||
return Promise.all([
|
||||
util.logout(agent),
|
||||
util.deleteTestFile('large.bin')
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('4 Invalid Request', () => {
|
||||
it('SHOULD NOT accept a request with no file attached', async () => {
|
||||
await util.createTestSession(agent);
|
||||
await verifyFailedUpload(null, 400, 'No file specified.');
|
||||
|
||||
|
||||
|
||||
|
||||
return util.logout(agent);
|
||||
})
|
||||
})
|
||||
});
|
||||
});*/
|
||||
});
|
||||
|
||||
after(() => server.close(() => process.exit(0)));
|
||||
|
150
test/testUtil.js
150
test/testUtil.js
@ -1,8 +1,5 @@
|
||||
process.env.NODE_ENV = 'test';
|
||||
|
||||
const app = require('../server');
|
||||
const server = app.server;
|
||||
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-http'));
|
||||
const should = chai.should();
|
||||
@ -11,6 +8,10 @@ const User = require('../app/models/User.js');
|
||||
const Invite = require('../app/models/Invite.js');
|
||||
const Upload = require('../app/models/Upload.js');
|
||||
|
||||
const Buffer = require('buffer').Buffer;
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs').promises;
|
||||
|
||||
//---------------- DATABASE UTIL ----------------//
|
||||
|
||||
exports.clearDatabase = async () =>
|
||||
@ -22,129 +23,58 @@ exports.clearDatabase = async () =>
|
||||
|
||||
//---------------- API ROUTES ----------------//
|
||||
|
||||
exports.login = async (credentials, agent) => {
|
||||
return (agent ? agent : chai.request(server))
|
||||
exports.login = async (credentials, agent) =>
|
||||
agent
|
||||
.post('/api/auth/login')
|
||||
.send(credentials);
|
||||
};
|
||||
|
||||
exports.createInvite = async (invite) => {
|
||||
if (!invite.code) invite.code = 'code';
|
||||
if (!invite.scope) invite.scope = ['test.perm', 'file.upload'];
|
||||
if (!invite.issuer) invite.issuer = 'Mocha';
|
||||
if (!invite.issued) invite.issued = new Date();
|
||||
return Invite.create(invite);
|
||||
};
|
||||
exports.logout = agent =>
|
||||
agent
|
||||
.post('/api/auth/logout');
|
||||
|
||||
exports.registerUser = async (user) => {
|
||||
if (!user.username) user.username = 'user';
|
||||
if (!user.password) user.password = 'pass';
|
||||
if (!user.invite) user.invite = 'code';
|
||||
return chai.request(server)
|
||||
exports.createInvite = async (invite) =>
|
||||
Invite.create(invite);
|
||||
|
||||
exports.registerUser = async (user, agent) =>
|
||||
agent
|
||||
.post('/api/auth/register')
|
||||
.send(user);
|
||||
};
|
||||
|
||||
exports.ping = async (agent) =>
|
||||
(agent ? agent : chai.request(server))
|
||||
.get('/api/auth/ping')
|
||||
exports.whoami = async (agent) =>
|
||||
agent
|
||||
.get('/api/auth/whoami')
|
||||
.send();
|
||||
|
||||
//---------------- TEST ENTRY CREATION ----------------//
|
||||
|
||||
exports.createTestInvite = async () =>
|
||||
exports.createInvite({});
|
||||
exports.createInvite({code: 'code', scope: ['file.upload']});
|
||||
|
||||
exports.createTestInvites = async (n) => {
|
||||
const codes = Array.from(new Array(n), (val, index) => 'code' + index);
|
||||
return Promise.all(codes.map(code => exports.createInvite({code: code})));
|
||||
};
|
||||
exports.createTestInvites = async (n) =>
|
||||
Promise.all(
|
||||
Array.from(new Array(n), (val, index) => 'code' + index)
|
||||
.map(code => exports.createInvite({code: code}))
|
||||
);
|
||||
|
||||
exports.createTestUser = async () => {
|
||||
exports.createTestUser = async agent => {
|
||||
await exports.createTestInvite();
|
||||
return exports.registerUser({});
|
||||
return exports.registerUser({username: 'user', password: 'pass', invite: 'code'}, agent);
|
||||
};
|
||||
|
||||
//---------------- UPLOAD API ----------------//
|
||||
exports.createTestSession = async agent => {
|
||||
await exports.createTestUser(agent);
|
||||
await exports.login({username: 'user', password: 'pass'}, agent);
|
||||
};
|
||||
|
||||
var upload = function(token, file, cb) {
|
||||
chai.request(server)
|
||||
exports.createTestFile = async (size, name) =>
|
||||
fs.writeFile(name, Buffer.allocUnsafe(size));
|
||||
|
||||
exports.deleteTestFile = async name =>
|
||||
fs.unlink(name);
|
||||
|
||||
//---------------- UPLOADS ----------------//
|
||||
|
||||
exports.upload = (file, agent) =>
|
||||
agent
|
||||
.post('/api/upload')
|
||||
.attach('file', file)
|
||||
.set('Authorization', 'Bearer ' + token)
|
||||
.end(cb);
|
||||
};
|
||||
|
||||
var loginUpload = function(user, cb) {
|
||||
login(user, function(err, res) {
|
||||
upload(res.body.token, 'test/test.png', cb);
|
||||
});
|
||||
};
|
||||
|
||||
var loginUploadFile = function(user, file, cb) {
|
||||
login(user, function(err, res) {
|
||||
upload(res.body.token, file, cb);
|
||||
});
|
||||
};
|
||||
|
||||
var verifySuccessfulUpload = function(user, done) {
|
||||
loginUpload(user, function(err, res) {
|
||||
res.should.have.status(200);
|
||||
res.body.should.have.be.a('object');
|
||||
res.body.should.have.property('url');
|
||||
res.body.should.have.property('name');
|
||||
expect(res.body.name).to.match(/^[a-z]{6}$/);
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
var verifyFailedSizeUpload = function(user, done) {
|
||||
loginUploadFile(user, 'test/large.bin', function(err, res) {
|
||||
res.should.have.status(413);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('message').eql('File too large.');
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
var verifyFailedPermissionUpload = function(user, done) {
|
||||
loginUpload(user, function(err, res) {
|
||||
res.should.have.status(403);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('message').eql('Permission error.');
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
var verifyFailedAuthUpload = function(done) {
|
||||
async.parallel([
|
||||
function(cb) {
|
||||
upload('bogus', 'test/test.png', function(err, res) {
|
||||
res.should.have.status(401);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('message').eql('UnauthorizedError: jwt malformed');
|
||||
cb();
|
||||
});
|
||||
},
|
||||
function(cb) {
|
||||
upload('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.' +
|
||||
'eyJpc3MiOiJzaGltYXBhbi5yb2NrcyIsImlhd' +
|
||||
'CI6MTUwNzkyNTAyNSwiZXhwIjoxNTM5NDYxMD' +
|
||||
'I1LCJhdWQiOiJ3d3cuc2hpbWFwYW4ucm9ja3M' +
|
||||
'iLCJzdWIiOiJUZXN0VXNlciIsInVzZXJuYW1l' +
|
||||
'IjoiVGVzdFVzZXIiLCJzY29wZSI6ImZpbGUud' +
|
||||
'XBsb2FkIn0.e746_BNNuxlbXKESKKYsxl6e5j' +
|
||||
'8JwmEFxO3zRf66tWo',
|
||||
'test/test.png',
|
||||
function(err, res) {
|
||||
res.should.have.status(401);
|
||||
res.body.should.be.a('object');
|
||||
res.body.should.have.property('message').eql('UnauthorizedError: invalid signature');
|
||||
cb();
|
||||
})
|
||||
}
|
||||
], function(err, res) {
|
||||
if (err) console.log(err);
|
||||
done();
|
||||
});
|
||||
};
|
||||
.attach('file', file);
|
||||
|
Loading…
Reference in New Issue
Block a user