Руководство для разработчиков

Встраивание внешнего UI через фрейм

В данной статье на примере ОС Ubuntu 20 и сервиса Roundcube описан процесс добавления в панель любого своего контента, размещенного на внешних ресурсах, в виде фреймов - как веб-страницы внутри веб-страницы панели.

Обратите внимание!
Пути к конфигурационным файлам и скриптам запуска apache2 и nginx в разных ОС могут отличаться.

Добавление нового пункта меню

  1. В папке /usr/local/mgr5/etc/xml создайте файл ispmgr_mod_testframe.xml со следующим содержимым:

    <?xml version="1.0" encoding="UTF-8"?>
    <mgrdata>
        <mainmenu level="admin+">
            <modernmenu>
                <node name="my_group">
                    <node name="testframe" />
                </node>
            </modernmenu>
        </mainmenu>
    
        <handler name="testframe.sh" type="xml">
            <func name="testframe" />
        </handler>
    
        <lang name="ru">
            <messages name="desktop">
                <msg name="modernmenu_my_group">Test</msg>
                <msg name="modernmenu_testframe">Test Form Frame</msg>
            </messages>
        </lang>
    </mgrdata>
    Пояснения:
    Таким образом в левом меню панели создается группа с названием Test, в ней пункт меню Test form frame, также в данном файле задается обработчик.
  2. Создайте файл-обработчик testframe.sh, добавьте в него следующие строчки:

    #!/bin/bash
    cat /usr/local/mgr5/addon/testframe.xml

      Это простейший обработчик, который возвращает статичное содержимое файла testframe.xml

     

  3. Поместите файл testframe.sh в папку /usr/local/mgr5/addon/  и дайте стандартные для обработчиков плагинов права:
    chmod 755 testframe.sh
    
  4.  testframe.xml - XML-описание формы, поместите его в /usr/local/mgr5/addon/ рядом с предыдущим файлом.

    <?xml version="1.0" encoding="UTF-8"?>
    <doc lang="ru" func="testframe" binary="/ispmgr">
        <metadata name="testframe" type="form" mgr="ispmgr">
            <form>
                <field name="frame" fullwidth="yes">
                    <frame name="roundcubeframe" forcetheme="yes" fullpage="yes" keepalive="yes" />
                </field>
            </form>
        </metadata>
        <messages name="testframe" checked="6b49a92f5cc5153c76b78446d0d74eb4">
            <msg name="title">Test Form Frame</msg>
            <msg name="frame">Frame</msg>
        </messages>
        <roundcubeframe>https://x.x.x.x:1501/roundcube/?_task=mail&amp;_mbox=INBOX</roundcubeframe>
    </doc>
    
    где x.x.x.x - ip-адрес вашей панели
  5. Перезагрузите панель командой в консоли:

    killall core

    После этого внизу левого меню должна появиться новая группа, в ней пункт меню Test Form Frame.

Дополнительные настройки

  1. Откройте файл testframe.xml на редактирование и исправьте ip-адрес в URL, указанном внутри тэга <roundcubeframe>, заменив его на ip-адрес своей панели. Все, кроме ip-адреса (протокол, порт, путь к Roundcube) можно оставить как есть. 
  2. После редактирования и сохранения файла XML-описания формы перезапускать панель не требуется.
  3. Для корректной работы формы необходимо разрешить показывать Roundcube в чужом фрейме - по умолчанию он разрешает показывать себя только во фреймах с совпадающим хостом и портом (в данном случае порт отличается - у панели по умолчанию порт 1500, у Roundcube, который ставится с панелью ispmanager - порт 1501).

    Есть 2 способа это сделать:

    • Отключение заголовка X-Frame-Options в конфигурационном файле

      Roundcube  

      1. Перейдите в папку /etc/roundcube и откройте на редактирование файл config.inc.php
      2. В конце файла добавьте

        строчку:

        $config['x_frame_options'] = '';

         

      3. С этой опцией Roundcube перестанет добавлять дефолтное значение SAMEORIGIN для заголовка X-Frame-Options. Изменение начнет действовать сразу после сохранения файла config.inc.php, ничего перезагружать не нужно.

       

    •   настройка заголовка Content-Security-Policy

      Использование заголовка X-Frame-Options позволяет задать только две опции, которые либо вообще запрещают показ контента во фрейме, либо разрешают показ только во фрейме с того же хоста и порта. Для того, чтобы наш контент был виден только в фрейме с какого-то другого хоста или порта, нужно использовать заголовок Content-Security-Policy.

      1.   Отключите заголовок X-Frame-Options, который по умолчанию добавляет Roundcube (см. инструкцию в предыдущем разделе)
      2.   Перейдите в папку  /etc/nginx/vhosts-includes и откройте на редактирование файл 

        roundcube-nginx.conf

          В секции, начинающейся со строки location ~ ^/roundcube/(.+\.php)$ {, а также в секции, начинающейся со строки location ~* ^/roundcube/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ { добавьте строку:

        add_header "Content-Security-Policy" "frame-ancestors x.x.x.x:1500";
        
        *** Замените x.x.x.x:1500 на ip-адрес и порт вашей панели
      3.   Для активации изменений перезагрузите nginx командой /etc/init.d/nginx restart

        Настройка заголовка Content-Security-Policy в Apache  

       Во многих случаях для показа контента во фрейме может потребоваться настроить заголовок **Content-Security-Policy ** в веб-сервере Apache.  В конфигурационный файл Apache соответствующего уровня (это может быть .htaccess для конкретной папки или конфигурационные файлы в /etc/apache2 или /etc/httpd  -  на ваше усмотрение) потребуется добавить следующий код, заменив хост и порт на используемые панелью:

      <IfModule mod_headers.c>
          Header set Content-Security-Policy "frame-ancestors 172.31.97.115:1500"
      </IfModule>

Опции фрейма

Для тега <frame> могут быть использованы следующие атрибуты:

  • keepalive - этот атрибут позволяет сохранить состояние фрейма при переключении на другие вкладки панели и последующем возврате на вкладку фрейма;
  • fullheight - заставляет фрейм растягиваться до нижней границы окна браузера;
  • fullpage - заставляет фрейм растягиваться от левого меню и полосы  в шапке панели до нижней и правой границы окна браузера, таким образом заполняя все место, которое занимала форма;
  • forcetheme - этот атрибут при отображении фрейма в панели со включенной темной темой применяет фильтр к контенту фрейма, пытаясь подстроить его цвета под темную тему панели. В зависимости от страницы или приложения, отображаемого во фрейме, использование этого атрибута может быть полезным или наоборот нежелательным.  
Обратите внимание!
  Чтобы каждый из указанных выше атрибутов начал действовать, нужно присвоить ему значение "yes"

Пример использования атрибутов <frame>:

<frame name="frame" forcetheme="yes" fullpage="yes" keepalive="yes" />

Этот фрейм будет растягиваться на все окно, кроме левого меню и шапки панели, будет сохраняться при переходе на другие вкладки панели и в темной теме пытаться подстроиться под цвета панели.

Обратите внимание!

 Внутри описания формы мы помещаем тэг <frame> внутри тэга <field>, задавая нужное имя фрейма (name="roundcubeframe") и описанные выше атрибуты.    

URL страницы, отображаемой во фрейме, нужно добавить внутри тэга <doc> как тэг, совпадающий по названию с именем фрейма в описании формы <roundcubeframe>:

https://ip-адрес:1501/roundcube/?_task=mail&amp;_mbox=INBOX</roundcubeframe>