'use strict'; /* global it:false */ /* global describe:false */ /* global before:false */ /* global after:false */ const async = require('async'), constants = require('../../constants.js'), common = require('./common.js'), database = require('../../database.js'), expect = require('expect.js'), http = require('http'), nock = require('nock'), os = require('os'), server = require('../../server.js'), superagent = require('superagent'), settings = require('../../settings.js'); describe('Cloudron API (pre-activation)', function () { var SERVER_URL = 'http://localhost:' + constants.PORT; before(function (done) { nock.cleanAll(); async.series([ server.start.bind(server), database._clear, settings._setApiServerOrigin.bind(null, 'http://localhost:6060'), settings.setBackupConfig.bind(null, { provider: 'filesystem', backupFolder: '/tmp', format: 'tgz', retentionPolicy: { keepWithinSecs: 10000 }, schedulePattern: '00 00 23 * * *' }) ], done); }); after(function (done) { database._clear(function (error) { expect(error).to.not.be.ok(); server.stop(done); }); }); it('device is in first time mode', function (done) { superagent.get(SERVER_URL + '/api/v1/cloudron/status') .end(function (err, res) { expect(res.statusCode).to.equal(200); expect(res.body.activated).to.not.be.ok(); done(err); }); }); it('fails due to missing setupToken', function (done) { superagent.post(SERVER_URL + '/api/v1/cloudron/activate') .send({ username: '', password: 'somepassword', email: 'admin@foo.bar' }) .end(function (error, result) { expect(result.statusCode).to.equal(400); done(); }); }); it('fails due to empty username', function (done) { superagent.post(SERVER_URL + '/api/v1/cloudron/activate') .query({ setupToken: 'somesetuptoken' }) .send({ username: '', password: 'ADSFsdf$%436', email: 'admin@foo.bar' }) .end(function (error, result) { expect(result.statusCode).to.equal(400); done(); }); }); it('fails due to empty password', function (done) { superagent.post(SERVER_URL + '/api/v1/cloudron/activate') .query({ setupToken: 'somesetuptoken' }) .send({ username: 'someuser', password: '', email: 'admin@foo.bar' }) .end(function (error, result) { expect(result.statusCode).to.equal(400); done(); }); }); it('fails due to empty email', function (done) { superagent.post(SERVER_URL + '/api/v1/cloudron/activate') .query({ setupToken: 'somesetuptoken' }) .send({ username: 'someuser', password: 'ADSF#asd546', email: '' }) .end(function (error, result) { expect(result.statusCode).to.equal(400); done(); }); }); it('fails due to wrong displayName type', function (done) { superagent.post(SERVER_URL + '/api/v1/cloudron/activate') .query({ setupToken: 'somesetuptoken' }) .send({ username: 'someuser', password: 'ADSF?#asd546', email: 'admin@foo.bar', displayName: 1234 }) .end(function (error, result) { expect(result.statusCode).to.equal(400); done(); }); }); it('fails due to invalid email', function (done) { superagent.post(SERVER_URL + '/api/v1/cloudron/activate') .query({ setupToken: 'somesetuptoken' }) .send({ username: 'someuser', password: 'ADSF#asd546', email: 'invalidemail' }) .end(function (error, result) { expect(result.statusCode).to.equal(400); done(); }); }); it('succeeds', function (done) { superagent.post(SERVER_URL + '/api/v1/cloudron/activate') .query({ setupToken: 'somesetuptoken' }) .send({ username: 'someuser', password: 'ADSF#asd546', email: 'admin@foo.bar', displayName: 'tester' }) .end(function (error, result) { expect(result.statusCode).to.equal(201); done(); }); }); it('fails the second time', function (done) { superagent.post(SERVER_URL + '/api/v1/cloudron/activate') .query({ setupToken: 'somesetuptoken' }) .send({ username: 'someuser', password: 'ADSF#asd546', email: 'admin@foo.bar' }) .end(function (error, result) { expect(result.statusCode).to.equal(409); done(); }); }); it('device left first time mode', function (done) { superagent.get(SERVER_URL + '/api/v1/cloudron/status') .end(function (err, res) { expect(res.statusCode).to.equal(200); expect(res.body.activated).to.be.ok(); done(); }); }); }); describe('Cloudron API (post activation)', function () { const { setup, cleanup, serverUrl, owner, user } = common; before(setup); after(cleanup); describe('config', function () { it('cannot get config without token', async function () { const response = await superagent.get(`${serverUrl}/api/v1/config`) .ok(() => true); expect(response.statusCode).to.equal(401); }); it('can get config (admin)', async function () { const response = await superagent.get(`${serverUrl}/api/v1/config`) .query({ access_token: owner.token }); expect(response.statusCode).to.equal(200); expect(response.body.apiServerOrigin).to.eql('http://localhost:6060'); expect(response.body.webServerOrigin).to.eql('https://cloudron.io'); expect(response.body.adminFqdn).to.eql(settings.dashboardFqdn()); expect(response.body.version).to.eql(constants.VERSION); expect(response.body.cloudronName).to.be.a('string'); }); it('can get config (non-admin)', async function () { const response = await superagent.get(`${serverUrl}/api/v1/config`) .query({ access_token: user.token }); expect(response.statusCode).to.equal(200); expect(response.body.apiServerOrigin).to.eql('http://localhost:6060'); expect(response.body.webServerOrigin).to.eql('https://cloudron.io'); expect(response.body.adminFqdn).to.eql(settings.dashboardFqdn()); expect(response.body.version).to.eql(constants.VERSION); expect(response.body.cloudronName).to.be.a('string'); }); }); describe('login', function () { it('cannot login without body', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .ok(() => true); expect(response.statusCode).to.equal(400); }); it('cannot login without username', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ password: owner.password }) .ok(() => true); expect(response.statusCode).to.equal(400); }); it('cannot login without password', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: owner.username }) .ok(() => true); expect(response.statusCode).to.equal(400); }); it('cannot login with empty username', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: '', password: owner.password }) .ok(() => true); expect(response.statusCode).to.equal(400); }); it('cannot login with empty password', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: owner.username, password: '' }) .ok(() => true); expect(response.statusCode).to.equal(400); }); it('cannot login with unknown username', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: 'somethingrandom', password: owner.password }) .ok(() => true); expect(response.statusCode).to.equal(401); }); it('cannot login with unknown email', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: 'randomgemail', password: owner.password }) .ok(() => true); expect(response.statusCode).to.equal(401); }); it('cannot login with wrong password', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: owner.username, password: owner.password.toUpperCase() }) .ok(() => true); expect(response.statusCode).to.equal(401); }); it('can login with username', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: owner.username, password: owner.password }); expect(response.statusCode).to.equal(200); expect(new Date(response.body.expires).toString()).to.not.be('Invalid Date'); expect(response.body.accessToken).to.be.a('string'); }); it('can login with uppercase username', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: owner.username.toUpperCase(), password: owner.password }); expect(response.statusCode).to.equal(200); expect(new Date(response.body.expires).toString()).to.not.be('Invalid Date'); expect(response.body.accessToken).to.be.a('string'); }); it('can login with email', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: owner.email, password: owner.password }); expect(response.statusCode).to.equal(200); expect(new Date(response.body.expires).toString()).to.not.be('Invalid Date'); expect(response.body.accessToken).to.be.a('string'); }); it('can login with uppercase email', async function () { const response = await superagent.post(`${serverUrl}/api/v1/cloudron/login`) .send({ username: owner.email.toUpperCase(), password: owner.password }); expect(response.statusCode).to.equal(200); expect(new Date(response.body.expires).toString()).to.not.be('Invalid Date'); expect(response.body.accessToken).to.be.a('string'); }); }); describe('logs', function () { it('logStream - requires event-stream accept header', async function () { const response = await superagent.get(`${serverUrl}/api/v1/cloudron/logstream/box`) .query({ access_token: owner.token, fromLine: 0 }) .ok(() => true); expect(response.statusCode).to.be(400); }); it('logStream - stream logs', function (done) { const options = { host: 'localhost', port: constants.PORT, path: '/api/v1/cloudron/logstream/box?lines=10&access_token=' + owner.token, headers: { 'Accept': 'text/event-stream', 'Connection': 'keep-alive' } }; // superagent doesn't work. maybe https://github.com/visionmedia/superagent/issues/420 const req = http.get(options, function (res) { var data = ''; res.on('data', function (d) { data += d.toString('utf8'); }); setTimeout(function checkData() { var dataMessageFound = false; expect(data.length).to.not.be(0); data.split('\n').forEach(function (line) { if (line.indexOf('id: ') === 0) { expect(parseInt(line.substr('id: '.length), 10)).to.be.a('number'); } else if (line.indexOf('data: ') === 0) { const message = JSON.parse(line.slice('data: '.length)).message; if (Array.isArray(message) || typeof message === 'string') dataMessageFound = true; } }); expect(dataMessageFound).to.be.ok(); req.destroy(); done(); }, 1000); res.on('error', done); }); req.on('error', done); }); }); describe('memory', function () { it('cannot get without token', async function () { const response = await superagent.get(`${serverUrl}/api/v1/cloudron/memory`) .ok(() => true); expect(response.statusCode).to.equal(401); }); it('succeeds (admin)', async function () { const response = await superagent.get(`${serverUrl}/api/v1/cloudron/memory`) .query({ access_token: owner.token }); expect(response.statusCode).to.equal(200); expect(response.body.memory).to.eql(os.totalmem()); expect(response.body.swap).to.be.a('number'); }); it('fails (non-admin)', async function () { const response = await superagent.get(`${serverUrl}/api/v1/cloudron/memory`) .query({ access_token: user.token }) .ok(() => true); expect(response.statusCode).to.equal(403); }); }); describe('languages', function () { it('succeeds', async function () { const response = await superagent.get(`${serverUrl}/api/v1/cloudron/languages`); expect(response.statusCode).to.equal(200); expect(response.body.languages).to.be.an('array'); expect(response.body.languages.indexOf('en')).to.not.equal(-1); }); }); });