diff options
-rwxr-xr-x | bin/vk_sms_checker.py | 75 | ||||
-rw-r--r-- | include/py/homekit/database/__init__.py | 10 | ||||
-rw-r--r-- | include/py/homekit/database/__init__.pyi | 4 | ||||
-rw-r--r-- | include/py/homekit/database/bots.py | 5 | ||||
-rw-r--r-- | include/py/homekit/database/mysql.py | 77 | ||||
-rw-r--r-- | include/py/homekit/modem/e3372.py | 20 | ||||
-rw-r--r-- | include/py/homekit/telegram/telegram.py | 2 | ||||
-rw-r--r-- | localwebsite/classes/TelegramBotClient.php | 37 | ||||
-rw-r--r-- | localwebsite/composer.json | 16 | ||||
-rw-r--r-- | localwebsite/composer.lock | 341 | ||||
-rw-r--r-- | localwebsite/config.php | 95 | ||||
-rwxr-xr-x | localwebsite/cron/check-vk-sms.php | 44 | ||||
-rw-r--r-- | localwebsite/engine/database.php | 131 | ||||
-rw-r--r-- | localwebsite/functions.php | 300 | ||||
-rw-r--r-- | localwebsite/init.php | 71 | ||||
-rwxr-xr-x | localwebsite/utils.php | 66 |
16 files changed, 151 insertions, 1143 deletions
diff --git a/bin/vk_sms_checker.py b/bin/vk_sms_checker.py new file mode 100755 index 0000000..07d9953 --- /dev/null +++ b/bin/vk_sms_checker.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +import __py_include +import re + +from html import escape +from typing import Optional +from homekit.config import AppConfigUnit, config +from homekit.modem import ModemsConfig, E3372 +from homekit.database import MySQLHomeDatabase +from homekit.telegram import send_message + +db: Optional[MySQLHomeDatabase] = None + + +class VkSmsCheckerConfig(AppConfigUnit): + NAME = 'vk_sms_checker' + + @classmethod + def schema(cls) -> Optional[dict]: + return { + 'modem': {'type': 'string', 'required': True} + } + + @staticmethod + def custom_validator(data): + if data['modem'] not in ModemsConfig(): + raise ValueError('invalid modem') + + +def get_last_time() -> int: + cur = db.cursor() + cur.execute("SELECT last_message_time FROM vk_sms LIMIT 1") + return int(cur.fetchone()[0]) + + +def set_last_time(timestamp: int) -> None: + cur = db.cursor() + cur.execute("UPDATE vk_sms SET last_message_time=%s", (timestamp,)) + db.commit() + + +def check_sms(): + modem = ModemsConfig()[config.app_config['modem']] + cl = E3372(modem['ip'], legacy_token_auth=modem['legacy_auth']) + messages = cl.sms_list() + messages.reverse() + + last_time = get_last_time() + new_last_time = None + results = [] + + if not messages: + return + + for m in messages: + if m['UnixTime'] <= last_time: + continue + new_last_time = m['UnixTime'] + if re.match(r'^vk', m['Phone'], flags=re.IGNORECASE) or re.match(r'vk', m['Content'], flags=re.IGNORECASE): + results.append(m) + + if results: + for m in results: + text = '<b>'+escape(m['Phone'])+'</b> ('+m['Date']+')' + text += "\n"+escape(m['Content']) + send_message(text=text, chat='vk_sms_checker') + + if new_last_time: + set_last_time(new_last_time) + + +if __name__ == '__main__': + db = MySQLHomeDatabase() + config.load_app(VkSmsCheckerConfig) + check_sms()
\ No newline at end of file diff --git a/include/py/homekit/database/__init__.py b/include/py/homekit/database/__init__.py index b50cbce..c958959 100644 --- a/include/py/homekit/database/__init__.py +++ b/include/py/homekit/database/__init__.py @@ -6,6 +6,7 @@ __all__ = [ 'get_clickhouse', 'SimpleState', + 'MySQLHomeDatabase', 'SensorsDatabase', 'InverterDatabase', 'BotsDatabase' @@ -14,12 +15,13 @@ __all__ = [ def __getattr__(name: str): if name in __all__: - if name.endswith('Database'): - file = name[:-8].lower() - elif 'mysql' in name: + ln = name.lower() + if 'mysql' in ln: file = 'mysql' - elif 'clickhouse' in name: + elif 'clickhouse' in ln: file = 'clickhouse' + elif name.endswith('Database'): + file = name[:-8].lower() else: file = 'simple_state' diff --git a/include/py/homekit/database/__init__.pyi b/include/py/homekit/database/__init__.pyi index 31aae5d..3c057dc 100644 --- a/include/py/homekit/database/__init__.pyi +++ b/include/py/homekit/database/__init__.pyi @@ -1,6 +1,6 @@ from .mysql import ( - get_mysql as get_mysql, - mysql_now as mysql_now + mysql_now as mysql_now, + MySQLHomeDatabase as MySQLHomeDatabase ) from .clickhouse import get_clickhouse as get_clickhouse diff --git a/include/py/homekit/database/bots.py b/include/py/homekit/database/bots.py index fb5f326..fae8fb6 100644 --- a/include/py/homekit/database/bots.py +++ b/include/py/homekit/database/bots.py @@ -1,6 +1,6 @@ import pytz -from .mysql import mysql_now, MySQLDatabase, datetime_fmt +from .mysql import mysql_now, MySQLDatabase, datetime_fmt, MySQLCredsConfig, MySQLCloudCredsConfig from ..api.types import ( SoundSensorLocation ) @@ -26,6 +26,9 @@ class OpenwrtLogRecord: class BotsDatabase(MySQLDatabase): + def creds(self) -> MySQLCredsConfig: + return MySQLCloudCredsConfig() + def add_openwrt_logs(self, lines: List[Tuple[datetime, str]], access_point: int): diff --git a/include/py/homekit/database/mysql.py b/include/py/homekit/database/mysql.py index fe97cd4..a0b73fa 100644 --- a/include/py/homekit/database/mysql.py +++ b/include/py/homekit/database/mysql.py @@ -1,47 +1,74 @@ import time import logging +from abc import ABC, abstractmethod from mysql.connector import connect, MySQLConnection, Error from typing import Optional -from ..config import config +from ..config import ConfigUnit -link: Optional[MySQLConnection] = None logger = logging.getLogger(__name__) - datetime_fmt = '%Y-%m-%d %H:%M:%S' -def get_mysql() -> MySQLConnection: - global link +class MySQLCredsConfig(ConfigUnit, ABC): + @classmethod + def schema(cls) -> Optional[dict]: + schema = {} + for k in ('host', 'database', 'user', 'password'): + schema[k] = dict(type='string', required=True) + return schema + - if link is not None: - return link +class MySQLHomeCredsConfig(MySQLCredsConfig): + NAME = 'mysql_home_creds' - link = connect( - host=config['mysql']['host'], - user=config['mysql']['user'], - password=config['mysql']['password'], - database=config['mysql']['database'], - ) - link.time_zone = '+01:00' - return link + +class MySQLCloudCredsConfig(MySQLCredsConfig): + NAME = 'mysql_cloud_creds' def mysql_now() -> str: return time.strftime('%Y-%m-%d %H:%M:%S') -class MySQLDatabase: - def __init__(self): - self.db = get_mysql() +class MySQLDatabase(ABC): + _enable_pings: bool + _link: MySQLConnection + _time_zone: Optional[str] + + @abstractmethod + def creds(self) -> MySQLCredsConfig: + pass + + def __init__(self, enable_pings=False, time_zone='+01:00'): + self._enable_pings = enable_pings + self._time_zone = time_zone + self._connect() + + def _connect(self): + c = self.creds() + self._link = connect( + host=c['host'], + user=c['user'], + password=c['password'], + database=c['database'], + ) + if self._time_zone: + self._link.time_zone = self._time_zone def cursor(self, **kwargs): - try: - self.db.ping(reconnect=True, attempts=2) - except Error as e: - logger.exception(e) - self.db = get_mysql() - return self.db.cursor(**kwargs) + if self._enable_pings: + try: + self._link.ping(reconnect=True, attempts=2) + except Error as e: + logger.exception(e) + self._connect() + return self._link.cursor(**kwargs) def commit(self): - self.db.commit() + self._link.commit() + + +class MySQLHomeDatabase(MySQLDatabase): + def creds(self) -> MySQLCredsConfig: + return MySQLHomeCredsConfig()
\ No newline at end of file diff --git a/include/py/homekit/modem/e3372.py b/include/py/homekit/modem/e3372.py index f68db5a..8164b88 100644 --- a/include/py/homekit/modem/e3372.py +++ b/include/py/homekit/modem/e3372.py @@ -1,6 +1,7 @@ import requests import xml.etree.ElementTree as ElementTree +from datetime import datetime from ..util import Addr from enum import Enum from ..http import HTTPMethod @@ -21,14 +22,14 @@ class Error(Enum): ERROR_WRONG_TOKEN = 125001 ERROR_WRONG_SESSION = 125002 ERROR_WRONG_SESSION_TOKEN = 125003 - - + + class WifiStatus(Enum): WIFI_CONNECTING = '900' WIFI_CONNECTED = '901' WIFI_DISCONNECTED = '902' WIFI_DISCONNECTING = '903' - + class Cradle(Enum): CRADLE_CONNECTING = '900' @@ -38,8 +39,8 @@ class Cradle(Enum): CRADLE_CONNECTFAILED = '904' CRADLE_CONNECTSTATUSNULL = '905' CRANDLE_CONNECTSTATUSERRO = '906' - - + + class MacroEVDOLevel(Enum): MACRO_EVDO_LEVEL_ZERO = '0' MACRO_EVDO_LEVEL_ONE = '1' @@ -47,8 +48,8 @@ class MacroEVDOLevel(Enum): MACRO_EVDO_LEVEL_THREE = '3' MACRO_EVDO_LEVEL_FOUR = '4' MACRO_EVDO_LEVEL_FIVE = '5' - - + + class MacroNetWorkType(Enum): MACRO_NET_WORK_TYPE_NOSERVICE = 0 MACRO_NET_WORK_TYPE_GSM = 1 @@ -127,7 +128,7 @@ class E3372: _get_raw_data: bool _headers: dict[str, str] _authorized: bool - + def __init__(self, addr: Addr, need_auth: bool = True, @@ -174,7 +175,7 @@ class E3372: def sms_count(self): self.auth() return self.request('sms/sms-count') - + def sms_send(self, phone: str, text: str): self.auth() return self.request('sms/send-sms', HTTPMethod.POST, { @@ -204,6 +205,7 @@ class E3372: messages = [] for message_elem in root.find('Messages').findall('Message'): message_dict = {child.tag: child.text for child in message_elem} + message_dict['UnixTime'] = int(datetime.strptime(message_dict['Date'], '%Y-%m-%d %H:%M:%S').timestamp()) messages.append(message_dict) return messages diff --git a/include/py/homekit/telegram/telegram.py b/include/py/homekit/telegram/telegram.py index f42363e..7d7471b 100644 --- a/include/py/homekit/telegram/telegram.py +++ b/include/py/homekit/telegram/telegram.py @@ -11,7 +11,7 @@ _logger = logging.getLogger(__name__) def send_message(text: str, chat: str, parse_mode: str = 'HTML', - disable_web_page_preview: bool = False,): + disable_web_page_preview: bool = False): data, token = _send_telegram_data(text, chat, parse_mode, disable_web_page_preview) req = requests.post('https://api.telegram.org/bot%s/sendMessage' % token, data=data) return req.json() diff --git a/localwebsite/classes/TelegramBotClient.php b/localwebsite/classes/TelegramBotClient.php deleted file mode 100644 index b9583ee..0000000 --- a/localwebsite/classes/TelegramBotClient.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php - -class TelegramBotClient { - - protected string $token; - - public function __construct(string $token) { - $this->token = $token; - } - - public function sendMessage(int $chat_id, string $text): bool { - $ch = curl_init(); - $url = 'https://api.telegram.org/bot'.$this->token.'/sendMessage'; - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); - curl_setopt($ch, CURLOPT_TIMEOUT, 10); - curl_setopt($ch, CURLOPT_POSTFIELDS, [ - 'chat_id' => $chat_id, - 'text' => $text, - 'parse_mode' => 'html', - 'disable_web_page_preview' => 1 - ]); - $body = curl_exec($ch); - curl_close($ch); - - $resp = jsonDecode($body); - if (!$resp['ok']) { - debugError(__METHOD__ . ': ' . $body); - return false; - } - - return true; - } - -}
\ No newline at end of file diff --git a/localwebsite/composer.json b/localwebsite/composer.json deleted file mode 100644 index 15ba2e5..0000000 --- a/localwebsite/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "ch1p/localwebsite.homekit", - "type": "project", - "require": { - "twig/twig": "^3.3", - "ext-mbstring": "*", - "ext-sockets": "*", - "ext-simplexml": "*", - "ext-curl": "*", - "ext-json": "*", - "ext-gmp": "*", - "ext-sqlite3": "*", - "giggsey/libphonenumber-for-php": "^8.12" - }, - "license": "MIT" -} diff --git a/localwebsite/composer.lock b/localwebsite/composer.lock deleted file mode 100644 index c09f57d..0000000 --- a/localwebsite/composer.lock +++ /dev/null @@ -1,341 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "aad58d1c2f9900517de6f62599845b12", - "packages": [ - { - "name": "giggsey/libphonenumber-for-php", - "version": "8.12.51", - "source": { - "type": "git", - "url": "https://github.com/giggsey/libphonenumber-for-php.git", - "reference": "a42d89a46797083a95aa48393485fdac22fcac94" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php/zipball/a42d89a46797083a95aa48393485fdac22fcac94", - "reference": "a42d89a46797083a95aa48393485fdac22fcac94", - "shasum": "" - }, - "require": { - "giggsey/locale": "^1.7|^2.0", - "php": ">=5.3.2", - "symfony/polyfill-mbstring": "^1.17" - }, - "require-dev": { - "pear/pear-core-minimal": "^1.9", - "pear/pear_exception": "^1.0", - "pear/versioncontrol_git": "^0.5", - "phing/phing": "^2.7", - "php-coveralls/php-coveralls": "^1.0|^2.0", - "symfony/console": "^2.8|^3.0|^v4.4|^v5.2", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "8.x-dev" - } - }, - "autoload": { - "psr-4": { - "libphonenumber\\": "src/" - }, - "exclude-from-classmap": [ - "/src/data/", - "/src/carrier/data/", - "/src/geocoding/data/", - "/src/timezone/data/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Joshua Gigg", - "email": "giggsey@gmail.com", - "homepage": "https://giggsey.com/" - } - ], - "description": "PHP Port of Google's libphonenumber", - "homepage": "https://github.com/giggsey/libphonenumber-for-php", - "keywords": [ - "geocoding", - "geolocation", - "libphonenumber", - "mobile", - "phonenumber", - "validation" - ], - "support": { - "irc": "irc://irc.appliedirc.com/lobby", - "issues": "https://github.com/giggsey/libphonenumber-for-php/issues", - "source": "https://github.com/giggsey/libphonenumber-for-php" - }, - "time": "2022-07-11T08:12:34+00:00" - }, - { - "name": "giggsey/locale", - "version": "2.2", - "source": { - "type": "git", - "url": "https://github.com/giggsey/Locale.git", - "reference": "9c1dca769253f6a3e81f9a5c167f53b6a54ab635" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/giggsey/Locale/zipball/9c1dca769253f6a3e81f9a5c167f53b6a54ab635", - "reference": "9c1dca769253f6a3e81f9a5c167f53b6a54ab635", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "require-dev": { - "ext-json": "*", - "pear/pear-core-minimal": "^1.9", - "pear/pear_exception": "^1.0", - "pear/versioncontrol_git": "^0.5", - "phing/phing": "^2.7", - "php-coveralls/php-coveralls": "^2.0", - "phpunit/phpunit": "^8.5|^9.5", - "symfony/console": "^5.0", - "symfony/filesystem": "^5.0", - "symfony/finder": "^5.0", - "symfony/process": "^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Giggsey\\Locale\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Joshua Gigg", - "email": "giggsey@gmail.com", - "homepage": "https://giggsey.com/" - } - ], - "description": "Locale functions required by libphonenumber-for-php", - "support": { - "issues": "https://github.com/giggsey/Locale/issues", - "source": "https://github.com/giggsey/Locale/tree/2.2" - }, - "time": "2022-04-06T07:33:59+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "time": "2021-02-19T12:13:01+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2021-05-27T09:27:20+00:00" - }, - { - "name": "twig/twig", - "version": "v3.3.2", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "21578f00e83d4a82ecfa3d50752b609f13de6790" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/21578f00e83d4a82ecfa3d50752b609f13de6790", - "reference": "21578f00e83d4a82ecfa3d50752b609f13de6790", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" - }, - "require-dev": { - "psr/container": "^1.0", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.3-dev" - } - }, - "autoload": { - "psr-4": { - "Twig\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Twig Team", - "role": "Contributors" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], - "time": "2021-05-16T12:14:13+00:00" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "ext-mbstring": "*", - "ext-sockets": "*", - "ext-simplexml": "*", - "ext-curl": "*", - "ext-json": "*", - "ext-gmp": "*", - "ext-sqlite3": "*" - }, - "platform-dev": [], - "plugin-api-version": "2.0.0" -} diff --git a/localwebsite/config.php b/localwebsite/config.php deleted file mode 100644 index 3c2bcf7..0000000 --- a/localwebsite/config.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php - -return [ - 'group' => 'www-data', - 'files_mode' => 0664, - 'dirs_mode' => 0775, - 'is_dev' => true, - 'static_public_path' => '/assets', - - 'openwrt_ip' => '192.168.1.1', - - 'inverterd_host' => '192.168.1.2', - 'inverterd_port' => 8305, - - 'pump_host' => '192.168.1.2', - 'pump_port' => 8307, - - 'temphumd_servers' => [ - // fill here, example: - 'hall' => ['192.168.1.3', 8306, 'Big Hall'/*, optional: config::TEMPHUMD_NO_HUM */], - ], - - // modem names (array keys) must match ipset names and - // routing table names on the openwrt router - // - // the order of the keys in the array must be the same - // as the order in which fwmark iptables rules are applied - 'modems' => [ - 'modem-example' => [ - 'ip' => '1.2.3.4', - 'label' => 'Modem Name', - 'short_label' => 'Mname', - 'legacy_token_auth' => false, - ], - ], - - // 'routing_smallhome_ip' => 'fill_me', - // 'routing_default' => 'fill_me', - - 'debug_backtrace' => true, - 'debug_file' => '.debug.log', - - 'twig_cache' => true, - 'templates' => [ - 'web' => [ - 'root' => 'templates-web', - 'cache' => 'cache/templates-web', - ], - ], - - 'static' => [ - 'app.css' => 12, - 'app.js' => 7, - 'polyfills.js' => 1, - 'modem.js' => 2, - 'inverter.js' => 2, - 'h265webjs-dist/h265webjs-v20221106.js' => 3, - 'h265webjs-dist/h265webjs-v20221106-reminified.js' => 1, - 'h265webjs-dist/missile.js' => 1, - ], - - 'cam_hls_access_key' => '', - 'cam_hls_proto' => 'http', // bool|callable - 'cam_hls_host' => '192.168.1.1', // bool|callable - 'cam_list' => [ - 'low' => [ - // fill me with names - ], - 'high' => [ - // fill me with names - ], - 'labels' => [ - // assoc array - ], - ], - - 'vk_sms_checker' => [ - 'telegram_token' => '', - 'telegram_chat_id' => '', - 'modem_name' => '', // reference to the 'modems' array - ], - - 'database_path' => getenv('HOME').'/.config/homekit.localwebsite.sqlite3', - - 'auth_cookie_host' => '', - 'auth_need' => false, // bool|callable - 'auth_pw_salt' => '', - - 'grafana_sensors_url' => '', - 'grafana_inverter_url' => '', - - 'ipcam_server_api_addr' => '', - - 'dhcp_hostname_overrides' => [], -]; diff --git a/localwebsite/cron/check-vk-sms.php b/localwebsite/cron/check-vk-sms.php deleted file mode 100755 index 5d1095a..0000000 --- a/localwebsite/cron/check-vk-sms.php +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env php -<?php - -// this scripts pulls recent inbox from e3372 modem, -// looks for new messages from vk and re-sends them -// to the telegram group - -require_once __DIR__.'/../init.php'; -global $config; - -$cfg = $config['modems'][$config['vk_sms_checker']['modem_name']]; -$e3372 = new E3372($cfg['ip'], $cfg['legacy_token_auth']); - -$db = getDB(); - -$last_processed = $db->querySingle("SELECT last_message_time FROM vk_processed"); -$new_last_processed = 0; - -$messages = $e3372->getSMSList(); -$messages = array_reverse($messages); - -$results = []; -if (!empty($messages)) { - foreach ($messages as $m) { - if ($m['timestamp'] <= $last_processed) - continue; - - $new_last_processed = $m['timestamp']; - if (preg_match('/^vk/i', $m['phone']) || preg_match('/vk/i', $m['content'])) - $results[] = $m; - } -} - -if (!empty($results)) { - $t = new TelegramBotClient($config['vk_sms_checker']['telegram_token']); - foreach ($results as $m) { - $text = '<b>'.htmlescape($m['phone']).'</b> ('.$m['date'].')'; - $text .= "\n".htmlescape($m['content']); - $t->sendMessage($config['vk_sms_checker']['telegram_chat_id'], $text); - } -} - -if ($new_last_processed != 0) - $db->exec("UPDATE vk_processed SET last_message_time=?", $new_last_processed);
\ No newline at end of file diff --git a/localwebsite/engine/database.php b/localwebsite/engine/database.php deleted file mode 100644 index 33f36cf..0000000 --- a/localwebsite/engine/database.php +++ /dev/null @@ -1,131 +0,0 @@ -<?php - -class database { - - const SCHEMA_VERSION = 2; - - protected SQLite3 $link; - - public function __construct(string $db_path) { - $will_create = !file_exists($db_path); - $this->link = new SQLite3($db_path); - if ($will_create) - setperm($db_path); - $this->link->enableExceptions(true); - $this->upgradeSchema(); - } - - protected function upgradeSchema() { - $cur = $this->getSchemaVersion(); - if ($cur == self::SCHEMA_VERSION) - return; - - if ($cur < 1) { - $this->link->exec("CREATE TABLE users ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username TEXT, - password TEXT - )"); - } - if ($cur < 2) { - $this->link->exec("CREATE TABLE vk_processed ( - last_message_time INTEGER - )"); - $this->link->exec("INSERT INTO vk_processed (last_message_time) VALUES (0)"); - } - $this->syncSchemaVersion(); - } - - protected function getSchemaVersion() { - return $this->link->query("PRAGMA user_version")->fetchArray()[0]; - } - - protected function syncSchemaVersion() { - $this->link->exec("PRAGMA user_version=".self::SCHEMA_VERSION); - } - - protected function prepareQuery(string $sql): string { - if (func_num_args() > 1) { - $mark_count = substr_count($sql, '?'); - $positions = array(); - $last_pos = -1; - for ($i = 0; $i < $mark_count; $i++) { - $last_pos = strpos($sql, '?', $last_pos + 1); - $positions[] = $last_pos; - } - for ($i = $mark_count - 1; $i >= 0; $i--) { - $arg_val = func_get_arg($i + 1); - if (is_null($arg_val)) { - $v = 'NULL'; - } else { - $v = '\''.$this->link->escapeString($arg_val) . '\''; - } - $sql = substr_replace($sql, $v, $positions[$i], 1); - } - } - - return $sql; - } - - public function query(string $sql, ...$params): SQLite3Result { - return $this->link->query($this->prepareQuery($sql, ...$params)); - } - - public function exec(string $sql, ...$params) { - return $this->link->exec($this->prepareQuery($sql, ...$params)); - } - - public function querySingle(string $sql, ...$params) { - return $this->link->querySingle($this->prepareQuery($sql, ...$params)); - } - - public function querySingleRow(string $sql, ...$params) { - return $this->link->querySingle($this->prepareQuery($sql, ...$params), true); - } - - protected function performInsert(string $command, string $table, array $fields): SQLite3Result { - $names = []; - $values = []; - $count = 0; - foreach ($fields as $k => $v) { - $names[] = $k; - $values[] = $v; - $count++; - } - - $sql = "{$command} INTO `{$table}` (`" . implode('`, `', $names) . "`) VALUES (" . implode(', ', array_fill(0, $count, '?')) . ")"; - array_unshift($values, $sql); - - return call_user_func_array([$this, 'query'], $values); - } - - public function insert(string $table, array $fields): SQLite3Result { - return $this->performInsert('INSERT', $table, $fields); - } - - public function replace(string $table, array $fields): SQLite3Result { - return $this->performInsert('REPLACE', $table, $fields); - } - - public function insertId(): int { - return $this->link->lastInsertRowID(); - } - - public function update($table, $rows, ...$cond): SQLite3Result { - $fields = []; - $args = []; - foreach ($rows as $row_name => $row_value) { - $fields[] = "`{$row_name}`=?"; - $args[] = $row_value; - } - $sql = "UPDATE `$table` SET " . implode(', ', $fields); - if (!empty($cond)) { - $sql .= " WHERE " . $cond[0]; - if (count($cond) > 1) - $args = array_merge($args, array_slice($cond, 1)); - } - return $this->query($sql, ...$args); - } - - -}
\ No newline at end of file diff --git a/localwebsite/functions.php b/localwebsite/functions.php deleted file mode 100644 index 6868b0d..0000000 --- a/localwebsite/functions.php +++ /dev/null @@ -1,300 +0,0 @@ -<?php - -function param($key) { - global $RouterInput; - - $val = null; - - if (isset($RouterInput[$key])) { - $val = $RouterInput[$key]; - } else if (isset($_POST[$key])) { - $val = $_POST[$key]; - } else if (isset($_GET[$key])) { - $val = $_GET[$key]; - } - - if (is_array($val)) { - $val = implode($val); - } - return $val; -} - -function str_replace_once(string $needle, string $replace, string $haystack): string { - $pos = strpos($haystack, $needle); - if ($pos !== false) { - $haystack = substr_replace($haystack, $replace, $pos, strlen($needle)); - } - return $haystack; -} - -function htmlescape($s) { - if (is_array($s)) { - foreach ($s as $k => $v) { - $s[$k] = htmlescape($v); - } - return $s; - } - return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); -} - -function jsonEncode($obj) { - return json_encode($obj, JSON_UNESCAPED_UNICODE); -} - -function jsonDecode($json) { - return json_decode($json, true); -} - -function startsWith(string $haystack, string $needle): bool { - return $needle === "" || strpos($haystack, $needle) === 0; -} - -function endsWith(string $haystack, string $needle): bool { - return $needle === "" || substr($haystack, -strlen($needle)) === $needle; -} - -function exectime($format = null) { - $time = round(microtime(true) - START_TIME, 4); - if (!is_null($format)) { - $time = sprintf($format, $time); - } - return $time; -} - -function stransi($s) { - static $colors = [ - 'black' => 0, - 'red' => 1, - 'green' => 2, - 'yellow' => 3, - 'blue' => 4, - 'magenta' => 5, - 'cyan' => 6, - 'white' => 7 - ]; - static $valid_styles = ['bold', 'fgbright', 'bgbright']; - - $s = preg_replace_callback('/<(?:e ([a-z, =]+)|\/e)>/', function($match) use ($colors, $valid_styles) { - if (empty($match[1])) { - return "\033[0m"; - } else { - $codes = []; - $args = preg_split('/ +/', $match[1]); - $fg = null; - $bg = null; - $styles = []; - foreach ($args as $arg) { - list($argname, $argvalue) = explode('=', $arg); - $err = false; - if ($argname == 'fg' || $argname == 'bg') { - if (isset($colors[$argvalue])) { - $$argname = $colors[$argvalue]; - } else { - $err = true; - } - } else if ($argname == 'style') { - $argstyles = array_filter(explode(',', $argvalue)); - foreach ($argstyles as $style) { - if (!in_array($style, $valid_styles)) { - $err = true; - break; - } - } - if (!$err) { - foreach ($argstyles as $style) { - $styles[$style] = true; - } - } - } else { - $err = true; - } - - if ($err) { - trigger_error(__FUNCTION__.": unrecognized argument {$arg}", E_USER_WARNING); - } - } - - if (!is_null($fg)) { - $codes[] = $fg + (isset($styles['fgbright']) ? 90 : 30); - } - if (!is_null($bg)) { - $codes[] = $bg + (isset($styles['bgbright']) ? 100 : 40); - } - if (isset($styles['bold'])) { - $codes[] = 1; - } - - return !empty($codes) ? "\033[".implode(';', $codes)."m" : ''; - } - }, $s); - return $s; -} - -function strgen($len = 10): string { - $buf = ''; - for ($i = 0; $i < $len; $i++) { - $j = mt_rand(0, 61); - if ($j >= 36) { - $j += 13; - } else if ($j >= 10) { - $j += 7; - } - $buf .= chr(48 + $j); - } - return $buf; -} - -function setperm($file, $is_dir = null) { - global $config; - - // chgrp - $gid = filegroup($file); - $gname = posix_getgrgid($gid); - if (!is_array($gname)) { - debugError(__FUNCTION__.": posix_getgrgid() failed on $gid", $gname); - } else { - $gname = $gname['name']; - } - if ($gname != $config['group']) { - if (!chgrp($file, $config['group'])) { - debugError(__FUNCTION__.": chgrp() failed on $file"); - } - } - - // chmod - $perms = fileperms($file); - $need_perms = is_dir($file) ? $config['dirs_mode'] : $config['files_mode']; - if (($perms & $need_perms) !== $need_perms) { - if (!chmod($file, $need_perms)) { - debugError(__FUNCTION__.": chmod() failed on $file"); - } - } -} - -function redirect($url, $preserve_utm = true, $no_ajax = false) { - if (PHP_SAPI != 'cli' && $_SERVER['REQUEST_METHOD'] == 'GET' && $preserve_utm) { - $proxy_params = ['utm_source', 'utm_medium', 'utm_content', 'utm_campaign']; - $params = []; - foreach ($proxy_params as $p) { - if (!empty($_GET[$p])) { - $params[$p] = (string)$_GET[$p]; - } - } - if (!empty($params)) { - if (($anchor_pos = strpos($url, '#')) !== false) { - $anchor = substr($url, $anchor_pos+1); - $url = substr($url, 0, $anchor_pos); - } - $url .= (strpos($url, '?') === false ? '?' : '&').http_build_query($params); - if ($anchor_pos !== false) { - $url .= '#'.$anchor; - } - } - } - - header('Location: ' . $url); - exit; -} - -function is_xhr_request(): bool { - return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'; -} - -function secondsToTime(int $n): string { - $parts = []; - - if ($n >= 86400) { - $days = floor($n / 86400); - $n %= 86400; - $parts[] = "{$days}д"; - } - - if ($n >= 3600) { - $hours = floor($n / 3600); - $n %= 3600; - $parts[] = "{$hours}ч"; - } - - if ($n >= 60) { - $minutes = floor($n / 60); - $n %= 60; - $parts[] = "{$minutes}мин"; - } - - if ($n) - $parts[] = "{$n}сек"; - - return implode(' ', $parts); -} - -function bytesToUnitsLabel(GMP $b): string { - $ks = array('B', 'Kb', 'Mb', 'Gb', 'Tb'); - foreach ($ks as $i => $k) { - if (gmp_cmp($b, gmp_pow(1024, $i + 1)) < 0) { - if ($i == 0) - return gmp_strval($b) . ' ' . $k; - - $n = gmp_intval(gmp_div_q($b, gmp_pow(1024, $i))); - return round($n, 2).' '.$k; - } - } - - return gmp_strval($b); -} - -function pwhash(string $s): string { - return hash('sha256', config::get('auth_pw_salt').'|'.$s); -} - -$ShutdownFunctions = []; - -function append_shutdown_function(callable $f) { - global $ShutdownFunctions; - $ShutdownFunctions[] = $f; -} - -function prepend_shutdown_function(callable $f) { - global $ShutdownFunctions; - array_unshift($ShutdownFunctions, $f); -} - -function getDB(): database { - static $link = null; - - if (is_null($link)) - $link = new database(config::get('database_path')); - - return $link; -} - -function to_camel_case(string $input, string $separator = '_'): string { - return lcfirst(str_replace($separator, '', ucwords($input, $separator))); -} - -function from_camel_case(string $s): string { - $buf = ''; - $len = strlen($s); - for ($i = 0; $i < $len; $i++) { - if (!ctype_upper($s[$i])) { - $buf .= $s[$i]; - } else { - $buf .= '_'.strtolower($s[$i]); - } - } - return $buf; -} - -function unsetcookie(string $name) { - global $config; - setcookie($name, null, -1, '/', $config['auth_cookie_host']); -} - -function setcookie_safe(...$args) { - global $config; - if (!headers_sent()) { - if (count($args) == 2) - setcookie($args[0], $args[1], time()+86400*365, '/', $config['auth_cookie_host']); - else - setcookie(...$args); - } -}
\ No newline at end of file diff --git a/localwebsite/init.php b/localwebsite/init.php deleted file mode 100644 index 4620ed2..0000000 --- a/localwebsite/init.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php - -error_reporting(E_ALL); -ini_set('display_errors', 1); - -mb_internal_encoding('UTF-8'); -mb_regex_encoding('UTF-8'); - -register_shutdown_function(function() { - global $ShutdownFunctions; - if (!empty($ShutdownFunctions)) { - foreach ($ShutdownFunctions as $f) - $f(); - } -}); - -spl_autoload_register(function($class) { - if (endsWith($class, 'Handler')) - $path = ROOT.'/handlers/'.$class.'.php'; - - // engine classes - else if (in_array($class, ['request_handler', 'router', 'model', 'debug', 'database'])) - $path = ROOT.'/engine/'.$class.'.php'; - - else if ($class == 'Lang') - $path = ROOT.'/engine/lang.php'; - - else if (endsWith($class, '_tpl')) - $path = ROOT.'/engine/tpl.php'; - - // other classes - else - $path = ROOT.'/classes/'.$class.'.php'; - - if (strpos($path, '\\') !== false) - $path = str_replace('\\', '/', $path); - - if (is_file($path)) - require_once $path; -}); - -define('ROOT', __DIR__); -define('START_TIME', microtime(true)); - -set_include_path(get_include_path().PATH_SEPARATOR.ROOT); - -require_once ROOT.'/functions.php'; - -$config = require ROOT.'/config.php'; -if (!is_file(ROOT.'/config.local.php')) - die('config.local.php not found'); -$config = array_merge($config, require_once ROOT.'/config.local.php'); - -// it's better to start logging as early as possible -$debug = debug::getInstance( - function($errno, $errfile, $errlne, $errstr) { - // it's not our fault that some vendor package uses something that's deprecated - // so let's not spam our logs - if ($errno == E_USER_DEPRECATED && startsWith($errfile, ROOT.'/vendor/')) - return false; - - return true; - } -); -$debug->setMessagesStoreType(debug::STORE_FILE); -$debug->setErrorsStoreType(debug::STORE_FILE); -$debug->enable(); -unset($debug); - -// composer -require_once ROOT.'/vendor/autoload.php'; diff --git a/localwebsite/utils.php b/localwebsite/utils.php deleted file mode 100755 index 333ebfc..0000000 --- a/localwebsite/utils.php +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env php -<?php - -require_once __DIR__.'/init.php'; - -function read_stdin(?string $prompt = null, bool $multiline = true) { - if (!is_null($prompt)) - echo $prompt; - - if (!$multiline) - return trim(fgets(STDIN)); - - $fp = fopen('php://stdin', 'r'); - $data = stream_get_contents($fp); - fclose($fp); - - return $data; -} - -function usage() { - global $argv; - echo <<<EOF -usage: {$argv[0]} COMMAND - -Supported commands: - add-user - change-password - -EOF; - exit(1); -} - -if (empty($argv[1])) - usage(); - -switch ($argv[1]) { - case 'add-user': - $username = read_stdin('enter username: ', false); - $password = read_stdin('enter password: ', false); - - if (users::exists($username)) { - fwrite(STDERR, "user already exists\n"); - exit(1); - } - - $id = users::add($username, $password); - echo "added user, id = $id\n"; - - break; - - case 'change-password': - $id = (int)read_stdin('enter ID: ', false); - if (!$id) - die("invalid id\n"); - - $password = read_stdin('enter new password: ', false); - if (!$password) - die("invalid password\n"); - - users::setPassword($id, $password); - break; - - default: - fwrite(STDERR, "invalid command\n"); - exit(1); -}
\ No newline at end of file |