Установка туннеля с ГИС ЖКХ под Linux

Задача установить защищенный туннель с ГИС ЖКХ под Astra Linux.

Решение:

Сначала скопируем с токена сертификат в формате pfx. Для этого можно воспользоваться утилитой P12FromGostCSP (Windows). Под Linux тоже как-то можно, но как- нужно гуглить. Мне предоставили уже готовый файл.

Далее нужно установить крипто-про CSP с пакетом stunnel. Зайдя в крипто про, во вкладке «сертификаты» необходимо установить корневые сертификаты с https://my.dom.gosuslugi.ru/ и установить сертификат из файла psk.

Для настройки конфигурационного файла stunnel, нужно из файла формата pfx получить файлы key и crt

crt и pem:

openssl pkcs12 -in file.pfx -clcerts -nokeys -out public.crt
openssl x509 -in public.crt -out public.pem -outform PEM

key:

openssl pkcs12 -in SSK_obezl_3.pfx -nocerts -out private.key

Лично у меня на этом месте выскочила ошибка:

Enter Import Password:
Error outputting keys and certificates
124867336299712:error:06074079:digital envelope routines:EVP_PBE_CipherInit:unknown pbe algorithm:../crypto/evp/evp_pbe.c:95:TYPE=1.2.840.113549.1.12.1.80
124867336299712:error:23077073:PKCS12 routines:PKCS12_pbe_crypt:pkcs12 algor cipherinit error:../crypto/pkcs12/p12_decr.c:41:
124867336299712:error:2306A075:PKCS12 routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error:../crypto/pkcs12/p12_decr.c:94:

Которую я так и не победил, но тем не менее файл сформировался.

Далее необходимо настроить конфигурационный файл туннеля. У меня он получился вида:

pid=/home/vasya/stunnel/stunnel_cli.pid
output=/home/vasya/stunnel/t.log
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
debug = 7
[https]
client = yes
accept=localhost:8080
connect = api.dom.gosuslugi.ru:443
cert=/home/vasya/stunnel/public.pem
CAFile=/home/vasya/stunnel/CA-PPAK_2023.pem
key=/home/vasya/stunnel/private.key
verify=0

Файл CA-PPAK_2023.pem взял из архива «ГИС ЖКХ_Интеграция v.14.8.0.2.zip» с документацией скачанного с сайта https://my.dom.gosuslugi.ru/

И пробуем запустить туннель:

opt/cprocsp/sbin/amd64/stunnel_thread /home/vasya/stunnel/stunnel_run.conf

Логи будут писаться в файл t.log. Если всё хорошо, и в логах ошибок нет, то можно попробовать выполнить в браузере запрос вида:

http://127.0.0.1:8080/ext-bus-debt-service/services/DebtAsync

От ГИС ЖКХ придет что-то вроде:

<env:Envelope xmlns:ns6="http://dom.gosuslugi.ru/schema/integration/individual-registry-base/" xmlns:ns5="http://dom.gosuslugi.ru/schema/integration/account-base/" xmlns:ns8="http://dom.gosuslugi.ru/schema/integration/metering-device-base/" xmlns:ns7="http://dom.gosuslugi.ru/schema/integration/nsi-base/" xmlns:ns13="http://dom.gosuslugi.ru/schema/integration/debts/" xmlns:ns9="http://dom.gosuslugi.ru/schema/integration/organizations-registry-base/" xmlns:ns12="http://dom.gosuslugi.ru/schema/integration/bills-base/" xmlns:ns11="http://dom.gosuslugi.ru/schema/integration/payments-base/" xmlns:ns10="http://dom.gosuslugi.ru/schema/integration/organizations-base/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns4="http://dom.gosuslugi.ru/schema/integration/base/" xmlns:ns3="http://www.w3.org/2000/09/xmldsig#">
   <env:Body>
      <env:Fault>
         <faultcode>env:Server</faultcode>
         <faultstring>AUT011000: Нет активной ИС с данным сертификатом</faultstring>
         <detail>
            <ns4:Fault>
               <ns4:ErrorCode>AUT011000</ns4:ErrorCode>
               <ns4:ErrorMessage>Нет активной ИС с данным сертификатом</ns4:ErrorMessage>
            </ns4:Fault>
         </detail>
      </env:Fault>
   </env:Body>
</env:Envelope>

Тут всё просто — открываем заявку на сайте ГИС ЖКХ и добавляем сертификат.

P,S. Отладку запросов далее можно делать в утилите soapui, Как? Тема отдельной будущей статьи, когда буду разбираться с запросами

nginx: отключить доступ к сайту по ip

Для того чтобы отключить доступ к сайту по url вида https://ip достаточно вверху конфигурации добавить строчки вида:

  listen 443 default_server;
  listen [::]:443 default_server;
  server_name _;
    
  ssl_certificate /etc/nginx/ssl/fullchain.pem;
  ssl_certificate_key /etc/nginx/ssl/cert.key;
        
    if ($host !~* ^(vasya.ru|www.vasya.ru)$ ) {
                return 444;
        }    
    return      444;
}

Вместо return 444, можно указать любую ошибку. Ну или сделать редирект на основной сайт, указав:

return 301 http://YOUR.DOMAIN;

JavaScript: Еще один вариант загрузки файла по клику на кнопку

Общая идея следующая: по клику на кнопку вызываем AJAX запрос на сервер с определенными параметрами передаваемыми в POST, затем получив в результат запроса файл — формируем в DOM на файл в формате blob, и тут-же её нажимаем. В результате браузер показывает диалоговое окно сохранения файла.

Таким необычным способом мы убиваем несколько зайцев сразу:

  1. Получаем возможность показать ошибку, если вдруг файл на сервере сформировать не удалось. Это полезно если например файл формируется на сервере «на лету» — например файл XLSX с отчётом
  2. Мы можем передать серверу какие-то условия для формирования файла в POST запросе
  3. На странице мы не размещаем заранее данные в тегах <form></form>, как практикуется в подобных решениях
  4. Пользователю достаточно нажать на кнопку один раз для получения результата.

В результате скрипт формирования файла может выглядеть примерно следующим образом:

На клиенте:

/**
 * Формирование отчета
 * @param {type} filename - имя файла на сервере для формирования отчета
 * @param {type} ext - выходное расширение (например xlsx,csv)
 * @returns {Number}
 */
function get_report(filename,ext){
        $("#global").addClass("loading");    
        var xhr = new XMLHttpRequest();
        xhr.open('POST', '?r=reports/'+filename, true);
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xhr.responseType = 'blob';     
        xhr.onload = function(e) {
            $("#global").removeClass("loading");    
            if (this.status == 200) {
                var link=document.createElement('a');
                link.href=window.URL.createObjectURL(this.response);                
                console.log("Расширение:"+ext);
                link.download="report."+ext;
                link.click();
            }
            else {
                console.log(e);
                ToastMessage("error","Произошла ошибка при формировании файла. Попробуйте позднее или обратитесь к администратору системы.");
            }
        };     
        var form_data = new Map();
        form_data.period_from = period_from.value;
        form_data.period_to = period_to.value;
        form_data.area = area_select.value;
        form_data.division_check=division_check.checked;
        form_data.period_check=period_check.checked;
        xhr.send(mapToQueryString(form_data));                                          
};

На сервере:

    public function actionGet_report_by_settlers(){               
       $request = Yii::$app->request;      
       $area= $request->post("area");
       $dir=Yii::$app->basePath."/web/templates";
        
      $oSpreadsheet = IOFactory::load($dir . "/report_1_1.xlsx");
      ...
      формируем файл эксель
      ...
      $oWriter = IOFactory::createWriter($oSpreadsheet, 'Xlsx');
      $oWriter->save('php://output');      
    };

CS-Cart: массовое удаление товара

Как ни странно, в CS-Cart нет явного функционала удаления всего товара. Разработчики предполагали, что администратор должен листать список в разделе «товары» и удалять по 50-100 товаров за раз (т.е. страницу максимум). Это долго и не наш путь..

Есть другой способ: в разделе «Категории», переместить все категории в «Корзину». Хотя в админке и есть кнопка «очистить корзину», по факту она оказалась не в состоянии удалить 15000+ товаров, а просто подвешивала весь сервер. Поэтому далее открываем консоль SSH, и из консоли выполняем:

/usr/bin/php  /var/www/www-root/data/www/каука.ru/g2.php -p --dispatch=categories.delete --category_id=код_категории

После чего ждем… По результату отработки скрипта весь товар с сайта будет удалён.

Если требуется удалить весь товар, НО! оставить все категории на месте, то можно пойти таким путём:

1) Выгрузить в файл id всех товаров:

      mysql -e  "use db; select product_id from cscart_products" | grep awk 'print {$1}' > list.log

      2) Скриптом удалить каждый товар:

      <?php
      $ls=file_get_contents("list.log");
      $products_a= explode("\n", $ls);
      foreach ($products_a as $id) {
          $rz=/usr/bin/php  /var/www/www-root/data/www/цувцув.ru/g2.php -p --dispatch=products.delete --product_id=$id;    
          var_dump($rz);
          echo "$id\n";
      }

      Chromedriver устаревших версий

      До версии 114 включительно, драйвера для тестирования можно было скачать по ссылке http://chromedriver.storage.googleapis.com/index.html Но с версии 115 и выше, гугл стал в открытом виде выкладывать chromedriver только для последних актуальных версий своего браузера. Тем не менее скачать вебдрайвер для «Устаревших» версий браузера остаётся возможным, но несколько надуманным способом.

      1. Открыть ссылку вида https://googlechromelabs.github.io/chrome-for-testing/127.0.6533.88.json, указав в URL необходимую версию
      2. В ответном json найти ссылку и скачать
      1 2 3 4 5 56