From 27e69c8e7fb468acc55a4970fe9ff6f6a757693f Mon Sep 17 00:00:00 2001 From: Pierre-Gilles Leymarie Date: Thu, 24 Oct 2019 16:29:56 +0200 Subject: [PATCH 1/4] Handle owntracks open api message server side --- .../lib/gateway/gateway.handleNewMessage.js | 52 +++++++++++-------- server/lib/index.js | 2 +- server/lib/location/index.js | 13 ++++- ...ation.handleNewGatewayOwntracksLocation.js | 27 ++++++++++ server/utils/constants.js | 1 + 5 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 server/lib/location/location.handleNewGatewayOwntracksLocation.js diff --git a/server/lib/gateway/gateway.handleNewMessage.js b/server/lib/gateway/gateway.handleNewMessage.js index e0039dd34c..cf88cdfa19 100644 --- a/server/lib/gateway/gateway.handleNewMessage.js +++ b/server/lib/gateway/gateway.handleNewMessage.js @@ -15,31 +15,31 @@ const { EVENTS } = require('../../utils/constants'); * }); */ async function handleNewMessage(data, rawMessage, cb) { - // first, we verify that the user has the right to control the instance - const usersKeys = JSON.parse(await this.variable.getValue('GLADYS_GATEWAY_USERS_KEYS')); - const rsaPublicKey = await this.gladysGatewayClient.generateFingerprint(rawMessage.rsaPublicKeyRaw); - const ecdsaPublicKey = await this.gladysGatewayClient.generateFingerprint(rawMessage.ecdsaPublicKeyRaw); + if (data.type === 'gladys-api-call') { + // first, we verify that the user has the right to control the instance + const usersKeys = JSON.parse(await this.variable.getValue('GLADYS_GATEWAY_USERS_KEYS')); + const rsaPublicKey = await this.gladysGatewayClient.generateFingerprint(rawMessage.rsaPublicKeyRaw); + const ecdsaPublicKey = await this.gladysGatewayClient.generateFingerprint(rawMessage.ecdsaPublicKeyRaw); - const found = usersKeys.find( - (user) => user.rsa_public_key === rsaPublicKey && user.ecdsa_public_key === ecdsaPublicKey, - ); + const found = usersKeys.find( + (user) => user.rsa_public_key === rsaPublicKey && user.ecdsa_public_key === ecdsaPublicKey, + ); - if ((!found || !found.accepted) && get(data, 'options.url') !== '/api/v1/user') { - cb({ - status: 403, - error: 'USER_NOT_ACCEPTED_LOCALLY', - message: 'User not allowed to control this Gladys instance', - }); - return; - } - if (!rawMessage.local_user_id && get(data, 'options.url') !== '/api/v1/user') { - cb({ - status: 400, - error: 'GATEWAY_USER_NOT_LINKED', - }); - return; - } - if (data.type === 'gladys-api-call') { + if ((!found || !found.accepted) && get(data, 'options.url') !== '/api/v1/user') { + cb({ + status: 403, + error: 'USER_NOT_ACCEPTED_LOCALLY', + message: 'User not allowed to control this Gladys instance', + }); + return; + } + if (!rawMessage.local_user_id && get(data, 'options.url') !== '/api/v1/user') { + cb({ + status: 400, + error: 'GATEWAY_USER_NOT_LINKED', + }); + return; + } try { const user = rawMessage.local_user_id ? await this.user.getById(rawMessage.local_user_id) : null; this.event.emit( @@ -62,6 +62,12 @@ async function handleNewMessage(data, rawMessage, cb) { } } } + + // if the message is an open API message + if (data.type === 'gladys-open-api' && data.action === 'create-owntracks-location') { + this.event.emit(EVENTS.GATEWAY.NEW_MESSAGE_OWNTRACKS_LOCATION, data.data); + cb({ status: 200 }); + } } module.exports = { diff --git a/server/lib/index.js b/server/lib/index.js index a3a95ee40f..0e7bc5fd40 100644 --- a/server/lib/index.js +++ b/server/lib/index.js @@ -55,10 +55,10 @@ function Gladys(params = {}) { const house = new House(event); const room = new Room(brain); const service = new Service(services, stateManager); - const location = new Location(); const message = new MessageHandler(event, brain, service); const session = new Session(params.jwtSecret, cache); const user = new User(session, stateManager, variable); + const location = new Location(user, event); const device = new Device(event, message, stateManager, service, room, variable); const scene = new Scene(stateManager, event, device); const scheduler = new Scheduler(event); diff --git a/server/lib/location/index.js b/server/lib/location/index.js index 0ce16d9481..1d7fd0bd26 100644 --- a/server/lib/location/index.js +++ b/server/lib/location/index.js @@ -1,11 +1,22 @@ const { create } = require('./location.create'); +const { handleNewGatewayOwntracksLocation } = require('./location.handleNewGatewayOwntracksLocation'); const { get } = require('./location.get'); const { getLast } = require('./location.getLast'); +const { EVENTS } = require('../../utils/constants'); +const { eventFunctionWrapper } = require('../../utils/functionsWrapper'); -const Location = function Location() {}; +const Location = function Location(user, event) { + this.user = user; + this.event = event; + this.event.on( + EVENTS.GATEWAY.NEW_MESSAGE_OWNTRACKS_LOCATION, + eventFunctionWrapper(this.handleNewGatewayOwntracksLocation.bind(this)), + ); +}; Location.prototype.create = create; Location.prototype.get = get; Location.prototype.getLast = getLast; +Location.prototype.handleNewGatewayOwntracksLocation = handleNewGatewayOwntracksLocation; module.exports = Location; diff --git a/server/lib/location/location.handleNewGatewayOwntracksLocation.js b/server/lib/location/location.handleNewGatewayOwntracksLocation.js new file mode 100644 index 0000000000..26dfae0b41 --- /dev/null +++ b/server/lib/location/location.handleNewGatewayOwntracksLocation.js @@ -0,0 +1,27 @@ +const logger = require('../../utils/logger'); +const { BadParameters } = require('../../utils/coreErrors'); + +/** + * @description Handle New Gateway Owntracks Location. + * @param {Object} data - Gateway data message. + * @example + * handleNewGatewayOwntracksLocation(data); + */ +async function handleNewGatewayOwntracksLocation(data) { + if (!data || !data.user_id || !data.latitude || !data.longitude) { + throw new BadParameters('user_id, latitude and longitude are required.'); + } + logger.debug(`Received new Owntracks location for user ${data.user_id}`); + const user = await this.user.getById(data.user_id); + const location = { + latitude: data.latitude, + longitude: data.longitude, + accuracy: data.accuracy, + altitude: data.altitude, + }; + await this.create(user.selector, location); +} + +module.exports = { + handleNewGatewayOwntracksLocation, +}; diff --git a/server/utils/constants.js b/server/utils/constants.js index a8511019a4..177f6862e0 100644 --- a/server/utils/constants.js +++ b/server/utils/constants.js @@ -38,6 +38,7 @@ const EVENTS = { CHECK_IF_BACKUP_NEEDED: 'gateway.check-if-backup-needed', RESTORE_BACKUP: 'gateway.restore-backup', NEW_MESSAGE_API_CALL: 'gateway.new-message-api-call', + NEW_MESSAGE_OWNTRACKS_LOCATION: 'gateway.new-message-owntracks-location', }, USER_SLEEP: { TIME_TO_WAKE_UP: 'user.time-to-wake-up', From df12d28369534cf436c5042a35ad7af5dd005776 Mon Sep 17 00:00:00 2001 From: Pierre-Gilles Leymarie Date: Thu, 24 Oct 2019 16:30:15 +0200 Subject: [PATCH 2/4] Add open API key to UI --- front/src/actions/gatewayLinkUser.js | 6 +- front/src/actions/login/loginGateway.js | 6 ++ front/src/components/app.jsx | 6 ++ .../components/gateway/GatewayLoginForm.jsx | 8 +++ front/src/config/i18n/en.json | 16 ++++- front/src/routes/settings/SettingsLayout.jsx | 13 ++++ .../settings-gateway-open-api/OpenApi.js | 71 +++++++++++++++++++ .../settings-gateway-open-api/OpenApiKey.js | 43 +++++++++++ .../settings-gateway-open-api/index.js | 64 +++++++++++++++++ 9 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 front/src/routes/settings/settings-gateway-open-api/OpenApi.js create mode 100644 front/src/routes/settings/settings-gateway-open-api/OpenApiKey.js create mode 100644 front/src/routes/settings/settings-gateway-open-api/index.js diff --git a/front/src/actions/gatewayLinkUser.js b/front/src/actions/gatewayLinkUser.js index 6770caa39a..58a6ae19c6 100644 --- a/front/src/actions/gatewayLinkUser.js +++ b/front/src/actions/gatewayLinkUser.js @@ -15,9 +15,13 @@ function createActions(store) { }); } catch (e) { console.log(e); + const error = get(e, 'response.error'); const errorMessage = get(e, 'response.error_message'); const errorMessageOtherFormat = get(e, 'response.message'); - if (errorMessage === 'NO_INSTANCE_FOUND' || errorMessageOtherFormat === 'NO_INSTANCE_DETECTED') { + if (error === 'LINKED_USER_NOT_FOUND') { + await state.session.gatewayClient.updateUserIdInGladys(null); + window.location = '/link-gateway-user'; + } else if (errorMessage === 'NO_INSTANCE_FOUND' || errorMessageOtherFormat === 'NO_INSTANCE_DETECTED') { store.setState({ usersGetStatus: RequestStatus.GatewayNoInstanceFound }); diff --git a/front/src/actions/login/loginGateway.js b/front/src/actions/login/loginGateway.js index 956e784f14..7f52b38cb1 100644 --- a/front/src/actions/login/loginGateway.js +++ b/front/src/actions/login/loginGateway.js @@ -85,7 +85,9 @@ function createActions(store) { route('/link-gateway-user'); } } catch (e) { + console.log(e); const error = get(e, 'response.error'); + const errorMessage = get(e, 'response.error_message'); // if user was previously linked to another instance, we reset the user id if (error === 'LINKED_USER_NOT_FOUND') { await state.session.gatewayClient.updateUserIdInGladys(null); @@ -94,6 +96,10 @@ function createActions(store) { store.setState({ gatewayLoginStatus: RequestStatus.UserNotAcceptedLocally }); + } else if (errorMessage === 'NO_INSTANCE_FOUND') { + store.setState({ + gatewayLoginStatus: RequestStatus.GatewayNoInstanceFound + }); } else { store.setState({ gatewayLoginStatus: RequestStatus.Error diff --git a/front/src/components/app.jsx b/front/src/components/app.jsx index a367f83527..1ee94d1b19 100644 --- a/front/src/components/app.jsx +++ b/front/src/components/app.jsx @@ -51,6 +51,7 @@ import SettingsGateway from '../routes/settings/settings-gateway'; import SettingsBackup from '../routes/settings/settings-backup'; import SettingsBilling from '../routes/settings/settings-billing'; import SettingsGatewayUsers from '../routes/settings/settings-gateway-users'; +import SettingsGatewayOpenApi from '../routes/settings/settings-gateway-open-api'; // Integrations import TelegramPage from '../routes/integration/all/telegram'; @@ -118,6 +119,11 @@ const AppRouter = connect( ) : ( )} + {config.gatewayMode ? ( + + ) : ( + + )} {!config.gatewayMode ? : } diff --git a/front/src/components/gateway/GatewayLoginForm.jsx b/front/src/components/gateway/GatewayLoginForm.jsx index 7816a134d6..99410a4030 100644 --- a/front/src/components/gateway/GatewayLoginForm.jsx +++ b/front/src/components/gateway/GatewayLoginForm.jsx @@ -27,6 +27,14 @@ const GatewayLoginForm = ({ children, ...props }) => ( )} + {props.gatewayLoginStatus === RequestStatus.GatewayNoInstanceFound && ( + + )} {props.gatewayLoginStatus === RequestStatus.NetworkError && (