Skip to content

Commit

Permalink
reorder things
Browse files Browse the repository at this point in the history
  • Loading branch information
mpfeil committed Oct 24, 2024
1 parent 7718867 commit 60283fc
Show file tree
Hide file tree
Showing 10 changed files with 319 additions and 56 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ lib-cov
*.gz
.vscode
.yarn-cache
.DS_Store

pids
logs
Expand Down
9 changes: 7 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
volumes:
opensensemap_backend:

services:
db:
image: timescale/timescaledb-ha:pg15-latest
image: timescale/timescaledb-ha:pg15.8-ts2.17.1
command:
- -cshared_preload_libraries=timescaledb,pg_cron
restart: always
Expand All @@ -9,4 +12,6 @@ services:
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=opensensemap
ports:
- 5432:5432
- 5432:5432
volumes:
- opensensemap_backend:/home/postgres/pgdata
15 changes: 8 additions & 7 deletions packages/api/lib/controllers/boxesController.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const
handleError = require('../helpers/errorHandler'),
jsonstringify = require('stringify-stream');
const { findDeviceById } = require('@sensebox/opensensemap-api-models/src/box/box');
const { createDevice, findDevices, findDevicesMinimal, findTags } = require('@sensebox/opensensemap-api-models/src/device');
const { createDevice, findDevices, findDevicesMinimal, findTags, updateDevice } = require('@sensebox/opensensemap-api-models/src/device');
const { findByUserId } = require('@sensebox/opensensemap-api-models/src/password');
const { getSensorsWithLastMeasurement } = require('@sensebox/opensensemap-api-models/src/sensor');
const { removeDevice, checkPassword } = require('@sensebox/opensensemap-api-models/src/user/user');
Expand Down Expand Up @@ -159,13 +159,14 @@ const { removeDevice, checkPassword } = require('@sensebox/opensensemap-api-mode
*/
const updateBox = async function updateBox (req, res) {
try {
let box = await Box.findBoxById(req._userParams.boxId, { lean: false, populate: false });
box = await box.updateBox(req._userParams);
if (box._sensorsChanged === true) {
req.user.mail('newSketch', box);
}
let device = await findDeviceById(req._userParams.boxId);
device = await updateDevice(device.id, req._userParams);
// if (box._sensorsChanged === true) {
// req.user.mail('newSketch', box);
// }

res.send({ code: 'Ok', data: box.toJSON({ includeSecrets: true }) });
// res.send({ code: 'Ok', data: box.toJSON({ includeSecrets: true }) });
res.send({ code: 'Ok', data: device });
clearCache(['getBoxes']);
} catch (err) {
return handleError(err);
Expand Down
4 changes: 3 additions & 1 deletion packages/api/lib/controllers/usersController.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ const { User } = require('@sensebox/opensensemap-api-models'),
refreshJwt,
invalidateToken,
} = require('../helpers/jwtHelpers');
const { createUser, findUserByNameOrEmail, checkPassword, initPasswordReset, resetOldPassword } = require('@sensebox/opensensemap-api-models/src/user/user');
const { checkPassword } = require('@sensebox/opensensemap-api-models/src/password/utils');
const { createUser } = require('@sensebox/opensensemap-api-models/src/user');
const { findUserByNameOrEmail, initPasswordReset, resetOldPassword } = require('@sensebox/opensensemap-api-models/src/user/user');

/**
* define for nested user parameter for box creation request
Expand Down
1 change: 0 additions & 1 deletion packages/models/src/box/box.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';

const { exposure } = require('../../schema/enum');
const { db } = require('../drizzle');

const { mongoose } = require('../db'),
Expand Down
122 changes: 120 additions & 2 deletions packages/models/src/device/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { deviceTable, sensorTable, accessTokenTable } = require('../../schema/sch
const sensorLayouts = require('../box/sensorLayouts');
const { db } = require('../drizzle');
const ModelError = require('../modelError');
const { inArray, arrayContains, sql } = require('drizzle-orm');
const { inArray, arrayContains, sql, eq } = require('drizzle-orm');
const { insertMeasurement, insertMeasurements } = require('../measurement');

const buildWhereClause = function buildWhereClause (opts = {}) {
Expand Down Expand Up @@ -112,7 +112,7 @@ const deleteDevice = async function (filter) {
.returning();
};

const findById = async function findById (deviceId, relations) {
const findById = async function findById (deviceId, relations = {}) {
const device = await db.query.deviceTable.findFirst({
where: (device, { eq }) => eq(device.id, deviceId),
...(Object.keys(relations).length !== 0 && { with: relations })
Expand Down Expand Up @@ -195,8 +195,126 @@ const saveMeasurements = async function saveMeasurements (device, measurements)
await insertMeasurements(measurements);
};

const updateDevice = async function updateDevice (deviceId, args) {
const {
mqtt: {
enabled,
url,
topic,
decodeOptions: mqttDecodeOptions,
connectionOptions,
messageFormat
} = {},
ttn: {
app_id,
dev_id,
port,
profile,
decodeOptions: ttnDecodeOptions
} = {},
location,
sensors,
addons: { add: addonToAdd } = {}
} = args;

if (args.mqtt) {
args['integrations.mqtt'] = {
enabled,
url,
topic,
decodeOptions: mqttDecodeOptions,
connectionOptions,
messageFormat
};
}
if (args.ttn) {
args['integrations.ttn'] = {
app_id,
dev_id,
port,
profile,
decodeOptions: ttnDecodeOptions
};
}

if (args.mqtt) {
args['integrations.mqtt'] = {
enabled,
url,
topic,
decodeOptions: mqttDecodeOptions,
connectionOptions,
messageFormat
};
}
if (args.ttn) {
args['integrations.ttn'] = {
app_id,
dev_id,
port,
profile,
decodeOptions: ttnDecodeOptions
};
}

const setColumns = {};
for (const prop of [
'name',
'exposure',
'grouptag',
'description',
'weblink',
'image',
// 'integrations.mqtt',
// 'integrations.ttn',
'model',
'useAuth'
]) {
if (typeof args[prop] !== 'undefined') {
setColumns[prop] = args[prop];

if (prop === 'grouptag') {
setColumns['tags'] = args[prop];
}
}
}

// TODO: generate new access token
// if user wants a new access_token
// if (typeof args['generate_access_token'] !== 'undefined') {
// if (args['generate_access_token'] === 'true') {
// // Create new acces token for box
// const access_token = crypto.randomBytes(32).toString('hex');
// box.set('access_token', access_token);
// }
// }

// TODO update sensors
// if (sensors) {
// box.updateSensors(sensors);
// } else if (addonToAdd) {
// box.addAddon(addonToAdd);
// }

// TODO: run location update logic, if a location was provided.
// const locPromise = location
// ? box
// .updateLocation(location)
// .then((loc) => box.set({ currentLocation: loc }))
// : Promise.resolve();

const device = await db
.update(deviceTable)
.set(setColumns)
.where(eq(deviceTable.id, deviceId))
.returning();

return device[0];
};

module.exports = {
createDevice,
updateDevice,
deleteDevice,
findById,
findDevices,
Expand Down
41 changes: 41 additions & 0 deletions packages/models/src/password/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

const bcrypt = require('bcrypt');
const crypto = require('crypto');

const ModelError = require('../modelError');

const { min_length: password_min_length, salt_factor: password_salt_factor } = require('config').get('openSenseMap-API-models.password');

const preparePasswordHash = function preparePasswordHash (plaintextPassword) {
// first round: hash plaintextPassword with sha512
const hash = crypto.createHash('sha512');
hash.update(plaintextPassword.toString(), 'utf8');
const hashed = hash.digest('base64'); // base64 for more entropy than hex

return hashed;
};

const checkPassword = function checkPassword (
plaintextPassword,
hashedPassword
) {
return bcrypt
.compare(preparePasswordHash(plaintextPassword), hashedPassword.hash)
.then(function (passwordIsCorrect) {
if (passwordIsCorrect === false) {
throw new ModelError('Password incorrect', { type: 'ForbiddenError' });
}

return true;
});
};

const validatePassword = function validatePassword (newPassword) {
return newPassword.length >= Number(password_min_length);
};

module.exports = {
checkPassword,
validatePassword
};
Loading

0 comments on commit 60283fc

Please sign in to comment.