GladysProject/Gladys

View on GitHub
server/lib/house/house.disarmWithCode.js

Summary

Maintainability
A
30 mins
Test Coverage
const Promise = require('bluebird');

const db = require('../../models');
const { ALARM_MODES, EVENTS } = require('../../utils/constants');
const { NotFoundError, ForbiddenError, TooManyRequests } = require('../../utils/coreErrors');

/**
 * @public
 * @description Disarm alarm with code.
 * @param {string} selector - Selector of the house.
 * @param {string} code - Code of the house.
 * @returns {Promise} Resolve when unlocked.
 * @example
 * await gladys.house.disarmWithCode('main-house', '123456');
 */
async function disarmWithCode(selector, code) {
  const house = await db.House.findOne({
    where: {
      selector,
    },
  });

  if (house === null) {
    throw new NotFoundError('House not found');
  }

  // We verify that the user is not requesting too much password test
  const rateLimitRes = await this.alarmCodeRateLimit.get(selector);

  // If there are no credits remaining
  if (rateLimitRes && rateLimitRes.remainingPoints === 0) {
    // Check scene triggers
    this.event.emit(EVENTS.TRIGGERS.CHECK, {
      type: EVENTS.ALARM.TOO_MANY_CODES_TESTS,
      house: selector,
    });
    throw new TooManyRequests('TOO_MANY_CODES_TESTS', rateLimitRes.msBeforeNext);
  }

  if (house.alarm_code !== code) {
    await this.alarmCodeRateLimit.consume(selector, 1);
    throw new ForbiddenError('INVALID_CODE');
  }

  // If code is right, delete all rate limit associated to this house
  await this.alarmCodeRateLimit.delete(selector);

  // In this case, we don't throw an error if the house is already disarmed
  if (house.alarm_mode === ALARM_MODES.DISARMED) {
    return house.get({ plain: true });
  }

  // Disarm house
  return this.disarm(selector);
}

module.exports = {
  disarmWithCode,
};