UNPKG

iobroker.homeconnect

Version:
538 lines (536 loc) 21.2 kB
module.exports = { /** * check all rate limiting json */ async checkLimitCounter() { const device_json = this.rateLimiting; const minutes_1 = 60 * 1000; const diff_1 = new Date().getTime() - device_json.requestsMinutesStartLast; if (diff_1 > minutes_1) { device_json.requestsMinutesStartCount = 0; device_json.requestsMinutesStartLast = new Date().getTime(); } const diff_2 = new Date().getTime() - device_json.requestsMinutesStopLast; if (diff_2 > minutes_1) { device_json.requestsMinutesStopCount = 0; device_json.requestsMinutesStopLast = new Date().getTime(); } const diff_50 = new Date().getTime() - device_json.requestsMinutesLast; if (diff_50 > minutes_1) { device_json.requestsMinutesCount = 0; device_json.requestsMinutesLast = new Date().getTime(); } const actualCW = this.getWeek(null); const blockCW = this.getWeek(device_json.requestsDayLast); if (actualCW !== blockCW) { device_json.requestsDayCount = 0; device_json.requestsDayLast = new Date().getTime(); device_json.requests = []; } const val = await this.checkBlock(); if (val) { await this.setLimitJson(false, 0); } else { await this.setState(`rateLimit.limitJson`, { val: JSON.stringify(this.rateLimiting), ack: true, }); } const minutes_10 = 10 * 60 * 1000; const diff_10 = new Date().getTime() - this.tokenRateLimiting.tokenRefreshMinutesLast; if (diff_10 > minutes_10 || diff_10 === minutes_10) { this.tokenRateLimiting.tokenRefreshMinutesCount = 0; this.tokenRateLimiting.tokenRefreshMinutesLast = new Date().getTime(); } const actualCWToken = this.getWeek(null); const blockCWToken = this.getWeek(this.tokenRateLimiting.tokenRefreshDayLast); if (actualCWToken !== blockCWToken) { this.tokenRateLimiting.tokenRefreshDayCount = 0; this.tokenRateLimiting.tokenRefreshDayLast = new Date().getTime(); } const token = await this.checkToken(true); if (!token) { await this.setState(`rateTokenLimit.limitJson`, { val: JSON.stringify(this.tokenRateLimiting), ack: true }); } }, /** * check rate limiting json * * @param {string} resp * @param {number} haId * @param {string} start * @param {string|null} url * @param {string|null} methode */ async setLimitCounter(resp, haId, start, url, methode) { if (resp === 'OK') { const minutes_1 = 60 * 1000; const diff_1 = new Date().getTime() - this.rateLimiting.requestsMinutesStartLast; if (diff_1 > minutes_1) { this.rateLimiting.requestsMinutesStartCount = 0; this.rateLimiting.requestsMinutesStartLast = new Date().getTime(); } const diff_2 = new Date().getTime() - this.rateLimiting.requestsMinutesStopLast; if (diff_2 > minutes_1) { this.rateLimiting.requestsMinutesStopCount = 0; this.rateLimiting.requestsMinutesStopLast = new Date().getTime(); } const diff_50 = new Date().getTime() - this.rateLimiting.requestsMinutesLast; if (diff_50 > minutes_1) { this.rateLimiting.requestsMinutesCount = 0; this.rateLimiting.requestsMinutesLast = new Date().getTime(); } const actualCW = this.getWeek(null); const blockCW = this.getWeek(this.rateLimiting.requestsDayLast); if (actualCW !== blockCW) { this.rateLimiting.requestsDayCount = 0; this.rateLimiting.requestsDayLast = new Date().getTime(); this.rateLimiting.requests = []; } if (url != null) { const json = { methode: methode, haId: haId, url: url, date: new Date().toISOString(), response: 'OK', }; this.rateLimiting.requests.push(json); } if (start === 'Start') { ++this.rateLimiting.requestsMinutesStartCount; if ( this.rateLimiting.requestReason != '5_Start_Requests_Minute' && (this.rateLimiting.requestsMinutesStartCount === this.rateLimiting.requestsMinutesStartMax || this.rateLimiting.requestsMinutesStartCount > this.rateLimiting.requestsMinutesStartMax) ) { this.rateLimiting.requestBlock = true; this.rateLimiting.requestBlockTime = new Date().getTime(); this.rateLimiting.requestReason = '5_Start_Requests_Minute'; this.log.error(`The limit of 5 start requests has been reached. Requests will be locked for 1 minute!`); ++this.rateLimiting.requestsMinutesCount; ++this.rateLimiting.requestsDayCount; await this.setLimitJson(true, 2); return; } } if (start === 'Stop') { ++this.rateLimiting.requestsMinutesStopCount; if ( this.rateLimiting.requestReason != '5_Stop_Requests_Minute' && (this.rateLimiting.requestsMinutesStopCount === this.rateLimiting.requestsMinutesStopMax || this.rateLimiting.requestsMinutesStopCount > this.rateLimiting.requestsMinutesStopMax) ) { this.rateLimiting.requestBlock = true; this.rateLimiting.requestBlockTime = new Date().getTime(); this.rateLimiting.requestReason = '5_Stop_Requests_Minute'; this.log.error(`The limit of 5 stop requests has been reached. Requests will be locked for 1 minute!`); ++this.rateLimiting.requestsMinutesCount; ++this.rateLimiting.requestsDayCount; await this.setLimitJson(true, 3); return; } } ++this.rateLimiting.requestsMinutesCount; if ( this.rateLimiting.requestReason != '50_Requests_Minute' && (this.rateLimiting.requestsMinutesCount === this.rateLimiting.requestsMinutesMax || this.rateLimiting.requestsMinutesCount > this.rateLimiting.requestsMinutesMax) ) { this.rateLimiting.requestBlock = true; this.rateLimiting.requestBlockTime = new Date().getTime(); this.rateLimiting.requestReason = '50_Requests_Minute'; this.log.error(`The limit of 50 requests per minute has been reached. Requests will be locked for 1 minute!`); ++this.rateLimiting.requestsDayCount; await this.setLimitJson(true, 4); return; } ++this.rateLimiting.requestsDayCount; if ( this.rateLimiting.requestReason != '1000_Requests_Day' && (this.rateLimiting.requestsDayCount === this.rateLimiting.requestsDayMax || this.rateLimiting.requestsDayCount > this.rateLimiting.requestsDayMax) ) { this.rateLimiting.requestBlock = true; this.rateLimiting.requestBlockTime = new Date().getTime(); this.rateLimiting.requestReason = '1000_Requests_Day'; this.log.error(`The limit of 1000 requests per day has been reached. Requests will be locked for this day!`); await this.setLimitJson(true, 5); return; } } else { const minutes = 10 * 60 * 1000; const diff_10 = new Date().getTime() - this.rateLimiting.responseErrorLast10MinutesLast; if (diff_10 > minutes) { this.rateLimiting.responseErrorLast10MinutesCount = 0; this.rateLimiting.responseErrorLast10MinutesLast = new Date().getTime(); } await this.setErrorResponse(false); ++this.rateLimiting.responseErrorLast10MinutesCount; if ( this.rateLimiting.requestReason != '10_Error_Minute' && (this.rateLimiting.responseErrorLast10MinutesCount === this.rateLimiting.responseErrorLast10MinutesMax || this.rateLimiting.responseErrorLast10MinutesCount > this.rateLimiting.responseErrorLast10MinutesMax) ) { this.rateLimiting.requestBlock = true; this.rateLimiting.requestBlockTime = new Date().getTime(); this.rateLimiting.requestReason = '10_Error_Minute'; this.log.error(`The limit of 10 error responses has been reached. Requests will be locked for 10 minutes!`); await this.setLimitJson(true, 1); return; } } await this.setLimitJson(false, 0); }, /** * set rate limiting json */ async checkBlock() { if (this.rateLimiting && this.rateLimiting.requestBlock) { const diff = new Date().getTime() - this.rateLimiting.requestBlockTime; const minute = 60 * 1000; if (this.rateLimiting.requestReason === '50_Requests_Minute') { if (diff < minute) { return false; } this.rateLimiting.requestsMinutesCount = 0; this.rateLimiting.requestsMinutesLast = new Date().getTime(); } else if (this.rateLimiting.requestReason === '5_Start_Requests_Minute') { if (diff < minute) { return false; } this.rateLimiting.requestsMinutesStartCount = 0; this.rateLimiting.requestsMinutesStartLast = new Date().getTime(); } else if (this.rateLimiting.requestReason === '5_Stop_Requests_Minute') { if (diff < minute) { return false; } this.rateLimiting.requestsMinutesStopCount = 0; this.rateLimiting.requestsMinutesStopLast = new Date().getTime(); } else if (this.rateLimiting.requestReason === '1000_Requests_Day') { const actualCW = this.getWeek(null); const blockCW = this.getWeek(this.rateLimiting.requestsDayLast); if (actualCW === blockCW) { return false; } this.rateLimiting.requestsDayCount = 0; this.rateLimiting.requestsDayLast = new Date().getTime(); this.rateLimiting.requests = []; } else if (this.rateLimiting.requestReason === '10_Error_Minute') { const minutes_10 = 10 * 60 * 1000; if (diff < minutes_10) { return false; } this.rateLimiting.responseErrorLast10MinutesCount = 0; this.rateLimiting.responseErrorLast10MinutesLast = new Date().getTime(); } this.rateLimiting.requestBlock = false; this.rateLimiting.requestBlockTime = new Date().getTime(); this.rateLimiting.requestReason = 'No Block'; } return true; }, /** * check token rate limiting json * * @param {boolean} check */ async checkToken(check) { if (this.tokenRateLimiting.tokenBlock) { if (this.tokenRateLimiting.tokenReason === '10_Minutes') { const minutes_10 = 10 * 60 * 1000; const diff_10 = new Date().getTime() - this.tokenRateLimiting.tokenBlockTime; if (diff_10 > minutes_10) { this.tokenRateLimiting.tokenBlock = false; this.tokenRateLimiting.tokenBlockTime = 0; this.tokenRateLimiting.tokenReason = 'No Block'; this.tokenRateLimiting.tokenRefreshMinutesCount = 0; this.tokenRateLimiting.tokenRefreshMinutesLast = new Date().getTime(); ++this.tokenRateLimiting.tokenRefreshMinutesCount; ++this.tokenRateLimiting.tokenRefreshDayCount; this.log.info(`10 minute token lock is unlock.`); await this.setTokenJson(false, 0); return true; } return false; } else if (this.tokenRateLimiting.tokenReason === 'Day') { const actualCW = this.getWeek(null); const blockCW = this.getWeek(this.tokenRateLimiting.tokenBlockTime); if (actualCW !== blockCW) { this.tokenRateLimiting.tokenBlock = false; this.tokenRateLimiting.tokenBlockTime = 0; this.tokenRateLimiting.tokenReason = 'No Block'; this.tokenRateLimiting.tokenRefreshDayCount = 0; this.tokenRateLimiting.tokenRefreshDayLast = new Date().getTime(); ++this.tokenRateLimiting.tokenRefreshMinutesCount; ++this.tokenRateLimiting.tokenRefreshDayCount; this.log.info(`Token lock is unlock.`); await this.setTokenJson(false, 0); return true; } return false; } this.tokenRateLimiting.tokenBlock = false; this.tokenRateLimiting.tokenBlockTime = 0; this.tokenRateLimiting.tokenReason = 'No Block'; } if (check) { return false; } const minutes_10 = 10 * 60 * 1000; const diff_10 = new Date().getTime() - this.tokenRateLimiting.tokenRefreshMinutesLast; if (diff_10 > minutes_10 || diff_10 === minutes_10) { this.tokenRateLimiting.tokenRefreshMinutesCount = 0; this.tokenRateLimiting.tokenRefreshMinutesLast = new Date().getTime(); } ++this.tokenRateLimiting.tokenRefreshMinutesCount; if ( diff_10 < minutes_10 && (this.tokenRateLimiting.tokenRefreshMinutesCount > this.tokenRateLimiting.tokenRefreshMinutesMax || this.tokenRateLimiting.tokenRefreshMinutesCount === this.tokenRateLimiting.tokenRefreshMinutesMax) ) { this.tokenRateLimiting.tokenBlock = true; this.tokenRateLimiting.tokenBlockTime = new Date().getTime(); this.tokenRateLimiting.tokenReason = '10_Minutes'; this.log.error(`The limit of 10 token requests has been reached. Refresh token will be locked for 10 minutes!`); await this.setTokenJson(true, 1); return false; } const actualCW = this.getWeek(null); const blockCW = this.getWeek(this.tokenRateLimiting.tokenRefreshDayLast); if (actualCW !== blockCW) { this.tokenRateLimiting.tokenRefreshDayCount = 0; this.tokenRateLimiting.tokenRefreshDayLast = new Date().getTime(); } ++this.tokenRateLimiting.tokenRefreshDayCount; if ( actualCW === blockCW && (this.tokenRateLimiting.tokenRefreshDayCount > this.tokenRateLimiting.tokenRefreshDayMax || this.tokenRateLimiting.tokenRefreshDayCount === this.tokenRateLimiting.tokenRefreshDayMax) ) { this.tokenRateLimiting.tokenBlock = true; this.tokenRateLimiting.tokenBlockTime = new Date().getTime(); this.tokenRateLimiting.tokenReason = 'Day'; this.log.error(`The limit of 100 token requests has been reached. Refresh token will be locked for this day!`); await this.setTokenJson(true, 2); return false; } await this.setTokenJson(false, 0); return true; }, /** * read rate limiting and token json * * @param {object} constants */ async getRateLimit(constants) { const dev = await this.getStateAsync(`rateLimit.limitJson`); if (dev && typeof dev.val === 'string' && dev.val.startsWith('{')) { const rate = JSON.parse(dev.val); if (Object.keys(rate).length != Object.keys(constants.rateLimiting).length) { this.rateLimiting = constants.rateLimiting; } else { this.rateLimiting = rate; } } else { this.rateLimiting = constants.rateLimiting; } const all = await this.getStateAsync(`rateTokenLimit.limitJson`); if (all && typeof all.val === 'string' && all.val.startsWith('{')) { const rate = JSON.parse(all.val); if (Object.keys(rate).length != Object.keys(constants.rateTokenLimiting).length) { this.tokenRateLimiting = constants.rateTokenLimiting; } else { this.tokenRateLimiting = rate; } } else { this.tokenRateLimiting = constants.rateTokenLimiting; } }, /** * Create Token Rate Limiting * */ async createLimit() { let common = {}; common = { name: { en: 'Token Rate Limiting', de: 'Token-Ratenbegrenzung', ru: 'Ограничение скорости токена', pt: 'Limitação de taxa de token', nl: 'Token tariefbeperking', fr: 'Limitation du taux de jetons', it: 'Limitazione della velocità del token', es: 'Limitación de la tasa de tokens', pl: 'Ograniczenie szybkości tokenów', uk: 'Обмеження швидкості токенів', 'zh-cn': '令牌速率限制', }, desc: 'Token Rate Limiting', }; await this.createDataPoint(`rateTokenLimit`, common, 'channel', null, null); common = { type: 'string', role: 'json', name: { en: 'Token Rate Limiting as JSON', de: 'Token-Ratenbegrenzung als JSON', ru: 'Ограничение скорости передачи токенов в формате JSON', pt: 'Limitação de taxa de token como JSON', nl: 'Tokensnelheidsbeperking als JSON', fr: 'Limitation du débit des jetons au format JSON', it: 'Limitazione della velocità del token come JSON', es: 'Limitación de la tasa de tokens como JSON', pl: 'Ograniczanie szybkości tokenów jako JSON', uk: 'Обмеження швидкості токенів у форматі JSON', 'zh-cn': 'JSON 格式的令牌速率限制', }, desc: 'Token Rate Limiting as JSON', read: true, write: false, def: '{}', }; await this.createDataPoint(`rateTokenLimit.limitJson`, common, 'state', null, null); common = { type: 'boolean', role: 'switch', name: { en: 'Blocking active', de: 'Sperrung aktiv', ru: 'Блокировка активна', pt: 'Bloqueio ativo', nl: 'Blokkering actief', fr: 'Blocage actif', it: 'Blocco attivo', es: 'Bloqueo activo', pl: 'Blokowanie aktywne', uk: 'Блокування активне', 'zh-cn': '阻断活动', }, desc: 'Blocking active', read: true, write: false, def: false, }; await this.createDataPoint(`rateTokenLimit.isBlocked`, common, 'state', null, null); common = { type: 'number', role: 'value', name: { en: 'Blocking reason', de: 'Sperrgrund', ru: 'Причина блокировки', pt: 'Motivo do bloqueio', nl: 'Reden voor blokkering', fr: 'Motif de blocage', it: 'Motivo del blocco', es: 'Motivo del bloqueo', pl: 'Powód blokowania', uk: 'Причина блокування', 'zh-cn': '阻止原因', }, desc: 'Blocking reason', read: true, write: false, def: 0, states: { 0: 'Nothing', 1: 'Token Limit (10 per minute)', 2: 'Token Limit (100 per day)', }, }; await this.createDataPoint(`rateTokenLimit.reason`, common, 'state', null, null); common = { name: { en: 'Rate Limiting', de: 'Ratenbegrenzung', ru: 'Ограничение скорости', pt: 'Limitação de taxa', nl: 'Snelheidsbeperking', fr: 'Limitation de débit', it: 'Limitazione della velocità', es: 'Limitación de velocidad', pl: 'Ograniczanie szybkości', uk: 'Обмеження швидкості', 'zh-cn': '速率限制', }, desc: 'Rate Limiting', }; await this.createDataPoint(`rateLimit`, common, 'channel', null, null); common = { type: 'string', role: 'json', name: { en: 'Rate Limiting as JSON', de: 'Ratenbegrenzung als JSON', ru: 'Ограничение скорости в формате JSON', pt: 'Limitação de taxa como JSON', nl: 'Snelheidsbeperking als JSON', fr: 'Limitation de débit en JSON', it: 'Limitazione della velocità come JSON', es: 'Limitación de velocidad como JSON', pl: 'Ograniczanie szybkości przesyłania danych jako JSON', uk: 'Обмеження швидкості у форматі JSON', 'zh-cn': 'JSON 格式的速率限制', }, desc: 'Rate Limiting as JSON', read: true, write: false, def: '{}', }; await this.createDataPoint(`rateLimit.limitJson`, common, 'state', null, null); common = { type: 'boolean', role: 'switch', name: { en: 'Blocking active', de: 'Sperrung aktiv', ru: 'Блокировка активна', pt: 'Bloqueio ativo', nl: 'Blokkering actief', fr: 'Blocage actif', it: 'Blocco attivo', es: 'Bloqueo activo', pl: 'Blokowanie aktywne', uk: 'Блокування активне', 'zh-cn': '阻断活动', }, desc: 'Blocking active', read: true, write: false, def: false, }; await this.createDataPoint(`rateLimit.isBlocked`, common, 'state', null, null); common = { type: 'number', role: 'value', name: { en: 'Blocking reason', de: 'Sperrgrund', ru: 'Причина блокировки', pt: 'Motivo do bloqueio', nl: 'Reden voor blokkering', fr: 'Motif de blocage', it: 'Motivo del blocco', es: 'Motivo del bloqueo', pl: 'Powód blokowania', uk: 'Причина блокування', 'zh-cn': '阻止原因', }, desc: 'Blocking reason', read: true, write: false, def: 0, states: { 0: 'Nothing', 1: 'Error Limit (10 per 10 minutes)', 2: 'Start Limit (5 per minute)', 3: 'Stop Limit (5 per minute)', 4: 'Request Limit (50 per minute)', 5: 'Request Limit (1000 per day)', }, }; await this.createDataPoint(`rateLimit.reason`, common, 'state', null, null); }, };