1С: проверка поручений МНП перед отправкой в НРД
Часть модуля onec-back, по умолчанию выключена, включается в настройках («Проверка поручений в 1С»). Исходящий перевод после блокировки бумаг в МНП ждёт решения 1С и в НРД не уходит, пока 1С не подтвердит каждое поручение; при отказе bj снимает поручения в QUIK с причиной из 1С и отклоняет перевод в журнале и кабинете клиента. - onec.instr / onec.instr_queue / onec.set_decision в базе bj: 1С читает очередь и пишет решение под логином onec_bj (только эти права); чтение очереди отмечает связь с 1С. - bj-onec-admin (root, через bj-keymedia): логин onec_bj, вход только с IP 1С по TLS (pg_hba.conf), listen_addresses, ufw; revoke закрывает вход. - onecLoop: отправка подтверждённых, отказы, снятие клиентом в QUIK, поручения из терминала, сроки решения и потеря связи — оповещения. - Карточка заявки: блок «Проверка 1С», решение оператора вместо 1С. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
@@ -17,6 +17,8 @@ process_one(){
|
||||
rng-status|rng-start|rng-cancel) out=$(/usr/local/sbin/bj-validata-rng "${action#rng-}" 2>&1) ;;
|
||||
# системные настройки сервера: серверы времени (NTP)
|
||||
system-ntp|system-tz|system-sync|system-ports) out=$(BJ_EXTRA="$extra" /usr/local/sbin/bj-system-admin "${action#system-}" 2>&1) ;;
|
||||
# вход 1С в базу bj (проверка поручений в 1С): логин onec_bj, pg_hba.conf; параметры — JSON в extra
|
||||
onec-access|onec-revoke) out=$(BJ_EXTRA="$extra" /usr/local/sbin/bj-onec-admin "${action#onec-}" 2>&1) ;;
|
||||
# резервное копирование и восстановление (настройки bj → bj-backup-admin); параметры — JSON в extra
|
||||
backup-config|backup-test|backup-run|backup-list|backup-verify|backup-restore) out=$(BJ_EXTRA="$extra" /usr/local/sbin/bj-backup-admin "${action#backup-}" 2>&1) ;;
|
||||
# Перезапуск службы модуля из админки. Список закрытый: чужую службу
|
||||
|
||||
Executable
+104
@@ -0,0 +1,104 @@
|
||||
#!/bin/bash
|
||||
# bj-onec-admin — вход 1С в базу PostgreSQL bj для проверки поручений в 1С (через root-демон bj-keymedia).
|
||||
# access — логин onec_bj с паролем, вход в базу bj только с IP сервера 1С и только по TLS:
|
||||
# свои строки в начале pg_hba.conf (# bj-onec), PostgreSQL слушает адрес сервера bj,
|
||||
# с которого виден сервер 1С (перезапуск PostgreSQL — только если этот адрес не слушался),
|
||||
# порт 5432 в ufw для IP 1С, если ufw включён. BJ_EXTRA: {"password":"…","ips":"10.0.0.5/32,…"}
|
||||
# revoke — закрыть вход: NOLOGIN, строки # bj-onec из pg_hba.conf и правила ufw убрать
|
||||
# Права на объекты onec.* выдаёт сам bj (он их владелец).
|
||||
set -uo pipefail
|
||||
q() { python3 -c "import json,sys;print(json.dumps(sys.argv[1],ensure_ascii=False))" "$1"; }
|
||||
ok() { echo "{\"ok\":true,\"output\":$(q "$1")${2:-}}"; exit 0; }
|
||||
err() { echo "{\"ok\":false,\"error\":$(q "$1")}"; exit 0; }
|
||||
x() { python3 -c "import json,os,sys;print(json.loads(os.environ.get('BJ_EXTRA') or '{}').get(sys.argv[1],''))" "$1" 2>/dev/null; }
|
||||
cd /
|
||||
psqlq() { runuser -u postgres -- psql -X -q -At -v ON_ERROR_STOP=1 "$@"; }
|
||||
LOGIN=onec_bj
|
||||
DB=bj
|
||||
MARK='# bj-onec'
|
||||
|
||||
hba=$(psqlq -d postgres -c 'show hba_file' 2>&1) || err "PostgreSQL недоступен: $hba"
|
||||
[ -f "$hba" ] || err "не найден pg_hba.conf ($hba)"
|
||||
|
||||
# hba_set "строки" — заменить наш блок (пусто — убрать) в начале pg_hba.conf
|
||||
hba_set() {
|
||||
[ -f "$hba.bak-bj-onec" ] || cp -a "$hba" "$hba.bak-bj-onec"
|
||||
python3 - "$hba" "$MARK" "$1" <<'PY' || return 1
|
||||
import sys
|
||||
p, mark, new = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
old = [l for l in open(p).read().split("\n") if not l.rstrip().endswith(mark)]
|
||||
add = [l for l in new.split("\n") if l.strip()]
|
||||
open(p, "w").write("\n".join(add + old).rstrip("\n") + "\n")
|
||||
PY
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
access)
|
||||
pw=$(x password); ips=$(x ips)
|
||||
[[ "$pw" =~ ^[A-Za-z0-9]{20,64}$ ]] || err "пароль: 20–64 латинских букв и цифр"
|
||||
list=()
|
||||
for ip in ${ips//,/ }; do
|
||||
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/(2[4-9]|3[0-2])$ ]] || err "недопустимый адрес 1С: $ip"
|
||||
list+=("$ip")
|
||||
done
|
||||
[ ${#list[@]} -gt 0 ] || err "не указан IP-адрес сервера 1С"
|
||||
[ "$(psqlq -d postgres -c 'show ssl')" = on ] || err "в PostgreSQL выключено шифрование (ssl = off) — 1С подключается только по TLS"
|
||||
psqlq -d postgres -c "select 1 from pg_database where datname='$DB'" | grep -q 1 || err "нет базы $DB"
|
||||
# логин: только вход, без прав на создание чего-либо; пароль — через переменную psql (не в командной строке)
|
||||
printf '%s\n' \
|
||||
"DO \$\$BEGIN IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '$LOGIN') THEN CREATE ROLE $LOGIN; END IF; END\$\$;" \
|
||||
"ALTER ROLE $LOGIN WITH LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS CONNECTION LIMIT 5 PASSWORD :'pw';" \
|
||||
"ALTER ROLE $LOGIN SET statement_timeout = '30s';" \
|
||||
"ALTER ROLE $LOGIN SET search_path = onec;" \
|
||||
| psqlq -d postgres -v pw="$pw" >/dev/null 2>&1 || err "логин $LOGIN не заведён"
|
||||
# в схеме public базы bj создавать объекты может только bj (у PUBLIC право снимаем)
|
||||
psqlq -d "$DB" -c "GRANT USAGE, CREATE ON SCHEMA public TO bj" -c "REVOKE CREATE ON SCHEMA public FROM PUBLIC" >/dev/null 2>&1 \
|
||||
|| err "права на схему public в базе $DB не изменены"
|
||||
lines=""
|
||||
for ip in "${list[@]}"; do lines+="hostssl $DB $LOGIN $ip md5 $MARK"$'\n'; done
|
||||
lines+="host all $LOGIN 0.0.0.0/0 reject $MARK"$'\n'"host all $LOGIN ::/0 reject $MARK"
|
||||
hba_set "$lines" || err "не удалось записать $hba"
|
||||
# адрес сервера bj, с которого виден сервер 1С
|
||||
first=${list[0]%/*}
|
||||
src=$(ip -o route get "$first" 2>/dev/null | sed -n 's/.* src \([0-9.]*\).*/\1/p' | head -1)
|
||||
[ -n "$src" ] || err "нет маршрута до сервера 1С ($first)"
|
||||
cur=$(psqlq -d postgres -c 'show listen_addresses')
|
||||
restart=no
|
||||
case ",${cur// /}," in
|
||||
*,\*,*|*,"$src",*|*,0.0.0.0,*) ;;
|
||||
*) new="${cur// /},$src"
|
||||
printf '%s\n' "ALTER SYSTEM SET listen_addresses = :'v';" | psqlq -d postgres -v v="$new" >/dev/null 2>&1 || err "listen_addresses не изменён"
|
||||
restart=yes ;;
|
||||
esac
|
||||
if [ "$restart" = yes ]; then
|
||||
systemctl restart postgresql >/dev/null 2>&1 || err "PostgreSQL не перезапустился (listen_addresses = $new)"
|
||||
for i in $(seq 1 30); do psqlq -d postgres -c 'select 1' >/dev/null 2>&1 && break; sleep 1; done
|
||||
else
|
||||
psqlq -d postgres -c 'select pg_reload_conf()' >/dev/null 2>&1 || err "PostgreSQL не перечитал pg_hba.conf"
|
||||
fi
|
||||
fw=""
|
||||
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q '^Status: active'; then
|
||||
for ip in "${list[@]}"; do ufw allow from "$ip" to any port 5432 proto tcp comment bj-onec >/dev/null 2>&1; done
|
||||
fw="; порт 5432 открыт в ufw"
|
||||
fi
|
||||
port=$(psqlq -d postgres -c 'show port')
|
||||
note="логин $LOGIN, вход с ${list[*]} по TLS, сервер $src:$port"
|
||||
[ "$restart" = yes ] && note+="; PostgreSQL теперь слушает $src (перезапущен)"
|
||||
ok "$note$fw" ",\"host\":$(q "$src"),\"port\":$(q "$port")"
|
||||
;;
|
||||
revoke)
|
||||
psqlq -d postgres -c "DO \$\$BEGIN IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '$LOGIN') THEN ALTER ROLE $LOGIN NOLOGIN; END IF; END\$\$;" >/dev/null 2>&1 \
|
||||
|| err "вход логином $LOGIN не закрыт"
|
||||
# открытые сеансы 1С — завершить
|
||||
psqlq -d postgres -c "select pg_terminate_backend(pid) from pg_stat_activity where usename = '$LOGIN'" >/dev/null 2>&1
|
||||
hba_set "" || err "не удалось записать $hba"
|
||||
psqlq -d postgres -c 'select pg_reload_conf()' >/dev/null 2>&1
|
||||
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q '^Status: active'; then
|
||||
while n=$(ufw status numbered 2>/dev/null | grep 'bj-onec' | head -1 | sed -n 's/^\[ *\([0-9]*\)\].*/\1/p') && [ -n "$n" ]; do
|
||||
ufw --force delete "$n" >/dev/null 2>&1 || break
|
||||
done
|
||||
fi
|
||||
ok "вход логином $LOGIN закрыт"
|
||||
;;
|
||||
*) err "команда: access | revoke" ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user