Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
daneryl committed Mar 20, 2019
2 parents 3d1083f + 0fb4c56 commit bc21623
Show file tree
Hide file tree
Showing 22 changed files with 338 additions and 51 deletions.
17 changes: 6 additions & 11 deletions app/api/auth/privateInstanceMiddleware.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import settings from '../settings';

const allowedRoutes = ['login', 'setpassword/'];
const allowedRoutes = ['login', 'setpassword/', 'unlockaccount/'];
const allowedRoutesMatch = new RegExp(allowedRoutes.join('|'));

const allowedApiCalls = ['/api/recoverpassword', '/api/resetpassword'];
const allowedApiCalls = ['/api/recoverpassword', '/api/resetpassword', '/api/unlockaccount'];
const allowedApiMatch = new RegExp(allowedApiCalls.join('|'));

const forbiddenRoutes = ['/api/', '/uploaded_documents/'];
Expand All @@ -16,18 +16,13 @@ export default function (req, res, next) {

return settings.get()
.then((result) => {
if (result.private && req.url.match(forbiddenRoutesMatch)) {
if (req.url.match(allowedApiMatch)) {
next();
if (result.private && !req.url.match(allowedApiMatch)) {
if (req.url.match(forbiddenRoutesMatch)) {
res.status(401);
res.json({ error: 'Unauthorized' });
return;
}

res.status(401);
res.json({ error: 'Unauthorized' });
return;
}

if (result.private) {
res.redirect('/login');
return;
}
Expand Down
10 changes: 10 additions & 0 deletions app/api/auth/specs/privateInstanceMiddleware.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ describe('privateInstanceMiddleware', () => {
req.url = 'host:port/api/resetpassword';
expectNextPromise(done);
});

it('should allow the unlockaccount endpoint', (done) => {
req.url = 'host:port/api/unlockaccount';
expectNextPromise(done);
});
});

describe('Other private-related calls', () => {
Expand Down Expand Up @@ -119,5 +124,10 @@ describe('privateInstanceMiddleware', () => {
req.url = 'url/setpassword/somehash';
expectNext();
});

it('should call next when instance is private and the url matches unlockaccount', () => {
req.url = 'url/unlockaccount/someAccount';
expectNext();
});
});
});
11 changes: 9 additions & 2 deletions app/api/documents/specs/__snapshots__/routes.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ Object {
"items": Array [
Object {
"children": Object {
"_id": Object {
"invalids": Array [
"",
],
"type": "string",
},
"filename": Object {
"invalids": Array [
"",
Expand Down Expand Up @@ -143,9 +149,10 @@ Object {
},
"timestamp": Object {
"invalids": Array [
"",
Infinity,
-Infinity,
],
"type": "string",
"type": "number",
},
},
"type": "object",
Expand Down
3 changes: 2 additions & 1 deletion app/api/entities/endpointSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ const saveSchema = Joi.object().keys({
})
})),
attachments: Joi.array().items(Joi.object().keys({
_id: Joi.string(),
originalname: Joi.string(),
filename: Joi.string(),
mimetype: Joi.string(),
size: Joi.number(),
timestamp: Joi.string(),
timestamp: Joi.number()
})),
creationDate: Joi.number(),
processed: Joi.boolean(),
Expand Down
11 changes: 9 additions & 2 deletions app/api/entities/specs/__snapshots__/routes.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,12 @@ Object {
"items": Array [
Object {
"children": Object {
"_id": Object {
"invalids": Array [
"",
],
"type": "string",
},
"filename": Object {
"invalids": Array [
"",
Expand Down Expand Up @@ -459,9 +465,10 @@ Object {
},
"timestamp": Object {
"invalids": Array [
"",
Infinity,
-Infinity,
],
"type": "string",
"type": "number",
},
},
"type": "object",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
export const rtlLanguagesList = [
'ar', 'dv', 'ha', 'he', 'ks', 'ku', 'ps', 'fa', 'ur', 'yi'
];

export default {
delta: 12,

name: 'add-RTL-to-settings-languages',

description: 'Adds the missing RTL value for existing instances with RTL languages',

rtlLanguagesList: ['ar', 'dv', 'ha', 'he', 'ks', 'ku', 'ps', 'fa', 'ur', 'yi'],

async up(db) {
process.stdout.write(`${this.name}...\r\n`);

Expand All @@ -18,7 +16,7 @@ export default {

languages = languages.map((l) => {
const migratedLanguage = l;
if (rtlLanguagesList.includes(l.key)) {
if (this.rtlLanguagesList.includes(l.key)) {
migratedLanguage.rtl = true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { catchErrors } from 'api/utils/jasmineHelpers';
import testingDB from 'api/utils/testing_db';
import migration, { rtlLanguagesList } from '../index.js';
import migration from '../index.js';
import fixtures from './fixtures.js';

describe('migration add-RTL-to-settings-languages', () => {
Expand All @@ -27,7 +27,7 @@ describe('migration add-RTL-to-settings-languages', () => {
expect(rtlLanguages.length).toBe(10);

rtlLanguages.forEach((language) => {
expect(rtlLanguagesList).toContain(language.key);
expect(migration.rtlLanguagesList).toContain(language.key);
});
});

Expand Down
2 changes: 1 addition & 1 deletion app/api/socketio/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default (server, app) => {
});

app.use((req, res, next) => {
req.io.getCurrentSessionSockets = () => {
req.getCurrentSessionSockets = () => {
const sessionSockets = {
sockets: [],
emit(...args) {
Expand Down
17 changes: 14 additions & 3 deletions app/api/socketio/specs/middleware.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,29 @@ describe('socketio middleware', () => {
});

it('should find and return an array of sockets belonging to the current cookie', () => {
let result = req.io.getCurrentSessionSockets();
let result = req.getCurrentSessionSockets();
expect(result.sockets[0]).toBe(socket1);
expect(result.sockets[1]).toBe(socket3);

req.session.id = 'sessionId2';
executeMiddleware(req, res, next);
result = req.io.getCurrentSessionSockets();
result = req.getCurrentSessionSockets();
expect(result.sockets[0]).toBe(socket2);
});

it('should isolate sockets for each requests when multiple requests are issued', () => {
const req1 = { ...req };
const req2 = { ...req, session: { id: 'sessionId2' } };
executeMiddleware(req1, res, next);
executeMiddleware(req2, res, next);
const req1Result = req1.getCurrentSessionSockets();
const req2Result = req2.getCurrentSessionSockets();
expect(req1Result.sockets).toEqual([socket1, socket3]);
expect(req2Result.sockets).toEqual([socket2]);
});

it('should include in the result an "emit" function that emits to all the found sockets the sent message', () => {
const result = req.io.getCurrentSessionSockets();
const result = req.getCurrentSessionSockets();
const data = { data: 'data' };

result.emit('Message', data);
Expand Down
6 changes: 3 additions & 3 deletions app/api/upload/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default (app) => {

const file = req.files[0].destination + req.files[0].filename;

const sessionSockets = req.io.getCurrentSessionSockets();
const sessionSockets = req.getCurrentSessionSockets();
sessionSockets.emit('conversionStart', req.body.document);
debugLog.debug(`Starting conversion of: ${req.files[0].originalname}`);
return Promise.all([
Expand Down Expand Up @@ -106,7 +106,7 @@ export default (app) => {
.then(() => {
debugLog.debug('Saving documents');
return entities.saveMultiple(docs.map(doc => ({ ...doc, file: { ...doc.file, timestamp: Date.now() } }))).then(() => {
const sessionSockets = req.io.getCurrentSessionSockets();
const sessionSockets = req.getCurrentSessionSockets();
sessionSockets.emit('documentProcessed', req.body.document);
});
});
Expand All @@ -120,7 +120,7 @@ export default (app) => {
entities.saveMultiple(docs.map(doc => ({ ...doc, processed: false })));
});

const sessionSockets = req.io.getCurrentSessionSockets();
const sessionSockets = req.getCurrentSessionSockets();
sessionSockets.emit('conversionFailed', req.body.document);
});

Expand Down
11 changes: 9 additions & 2 deletions app/api/upload/specs/routes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ describe('upload routes', () => {
spyOn(search, 'delete').and.returnValue(Promise.resolve());
spyOn(entities, 'indexEntities').and.returnValue(Promise.resolve());
iosocket = jasmine.createSpyObj('socket', ['emit']);
const io = { getCurrentSessionSockets: () => ({ sockets: [iosocket], emit: iosocket.emit }) };
routes = instrumentRoutes(uploadRoutes);
file = {
fieldname: 'file',
Expand All @@ -82,7 +81,15 @@ describe('upload routes', () => {
path: `${__dirname}/uploads/f2082bf51b6ef839690485d7153e847a.pdf`,
size: 171411271
};
req = { language: 'es', user: 'admin', headers: {}, body: { document: 'sharedId1' }, files: [file], io };
req = {
language: 'es',
user: 'admin',
headers: {},
body: { document: 'sharedId1' },
files: [file],
io: {},
getCurrentSessionSockets: () => ({ sockets: [iosocket], emit: iosocket.emit })
};

db.clearAllAndLoad(fixtures).then(done).catch(catchErrors(done));
spyOn(errorLog, 'error'); //just to avoid annoying console output
Expand Down
10 changes: 10 additions & 0 deletions app/api/users/specs/users.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ describe('Users', () => {
})
.catch(catchErrors(done)));

it('should not save a null password on update', async () => {
const user = { _id: recoveryUserId, role: 'admin' };

const [userInDb] = await users.get(recoveryUserId, '+password');
await users.save(user, { _id: userId, role: 'admin' });
const [updatedUser] = await users.get(recoveryUserId, '+password');

expect(updatedUser.password.toString()).toBe(userInDb.password.toString());
});

describe('when you try to change role', () => {
it('should be an admin', (done) => {
currentUser = { _id: userId, role: 'editor' };
Expand Down
25 changes: 12 additions & 13 deletions app/api/users/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,20 @@ const sendAccountLockedEmail = (user, domain) => {
};

export default {
save(user, currentUser) {
return model.get({ _id: user._id })
.then(async ([userInTheDatabase]) => {
if (user._id === currentUser._id.toString() && user.role !== currentUser.role) {
return Promise.reject(createError('Can not change your own role', 403));
}
async save(user, currentUser) {
const [userInTheDatabase] = await model.get({ _id: user._id }, '+password');

if (user.hasOwnProperty('role') && user.role !== userInTheDatabase.role && currentUser.role !== 'admin') {
return Promise.reject(createError('Unauthorized', 403));
}
if (user._id === currentUser._id.toString() && user.role !== currentUser.role) {
return Promise.reject(createError('Can not change your own role', 403));
}

if (user.hasOwnProperty('role') && user.role !== userInTheDatabase.role && currentUser.role !== 'admin') {
return Promise.reject(createError('Unauthorized', 403));
}

return model.save({
...user,
password: user.password ? await encryptPassword(user.password) : undefined,
});
return model.save({
...user,
password: user.password ? await encryptPassword(user.password) : userInTheDatabase.password,
});
},

Expand Down
2 changes: 1 addition & 1 deletion app/react/App/scss/elements/_controls.scss
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ input[type="checkbox"][disabled] ~ label {
cursor: not-allowed;
}

.icon-selector {
.icon-selector, .clear-field-button {
button {
background: none;
border: none;
Expand Down
24 changes: 23 additions & 1 deletion app/react/Forms/components/Geolocation.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Map from 'app/Map/Map';
import { Translate } from 'app/I18N';

function isCoordValid(coord) {
// eslint-disable-next-line no-restricted-globals
return typeof coord === 'number' && !isNaN(coord);
}

export default class Geolocation extends Component {
constructor(props) {
super(props);
this.latChange = this.latChange.bind(this);
this.lonChange = this.lonChange.bind(this);
this.mapClick = this.mapClick.bind(this);
this.clearCoordinates = this.clearCoordinates.bind(this);
}

onChange(value) {
if (!isCoordValid(value.lat) && !isCoordValid(value.lon)) {
this.props.onChange();
return;
}
this.props.onChange(value);
}

Expand All @@ -28,6 +39,10 @@ export default class Geolocation extends Component {
this.onChange({ lat: parseFloat(event.lngLat[1]), lon: parseFloat(event.lngLat[0]) });
}

clearCoordinates() {
this.props.onChange();
}

render() {
const markers = [];
const { value } = this.props;
Expand All @@ -39,7 +54,7 @@ export default class Geolocation extends Component {
lon = value.lon;
}

if (lat && lon) {
if (isCoordValid(lat) && isCoordValid(lon)) {
markers.push({ latitude: parseFloat(value.lat), longitude: parseFloat(value.lon) });
}
return (
Expand All @@ -55,6 +70,13 @@ export default class Geolocation extends Component {
<input onChange={this.lonChange} className="form-control" type="number" id="lon" value={lon} step="any"/>
</div>
</div>
{ (isCoordValid(lat) || isCoordValid(lon)) && (
<div className="clear-field-button">
<button type="button" onClick={this.clearCoordinates}>
<Translate>Clear coordinates</Translate>
</button>
</div>
)}
</div>
);
}
Expand Down
Loading

0 comments on commit bc21623

Please sign in to comment.