Пользовательский JavaScript и CSS на мобильных устройствах



    Хочется странного


    Если вы регулярно посещаете с мобильного устройства (телефона, планшета) какие-нибудь сайты, и если у вас регулярно возникает желание изменить на них JS/CSS (но разработчикам сайтов вы по какой-то причине не сообщаете об этих желаниях), то статья вам может быть интересна.



    Возможно вас, как и меня, устроил бы вариант с прокси, который будет выполнять нужную вам подмену. Посмотрим, что можно сделать.

    Давай покрасим холодильник…


    В целом, спектр возможностей видится широкий: изменение «темы» сайты, размеров отдельных элементов, исправление ошибок JS/CSS, включение спрятанных возможностей (к примеру, на VK есть HTML5 плеер, который не активен), или отключение имеющихся, вроде заботливо расставленных на сайте «ховеров», из-за которых на мобильных устройствах по ссылкам приходится тыкать два раза, и т.д. Но увы, в стандартных браузерах большей части устройств нет механизмов для реализации UserCSS или UserScript. Где-то работают букмарклеты (и я даже написал для себя около десятка), но процесс их «приготовления» нельзя назвать быстрым. В случае, если количество правок растёт (или уменьшается), постоянно править «закладурки» становится неудобно.

    В общем, как это можно решить:
    • находим хостинг с Apache или nginx
    • включаем там 2 расширения: прокси и что-то, что позволит менять проходящие через прокси файлы
    • настраиваем заменялку так, чтобы она подключала к страницам нужные вам JS/CSS
    • прописываем прокси на устройстве
    • профит

    У меня «хостинг» нашелся с Apache, его я и мучил.

    Injection


    Включить прокси на Apache несложно, сложнее оказалось с подменой контента на лету. Расширений «на рынке» несколько: mod_substitute, mod_filter, mod_sar. mod_sar я тупо не смог собрать, у mod_substitute были проблемы сначала со сжатыми страницами (пришлось собирать цепочку из фильтров распаковки-замены-упаковки, чтобы работало), потом обнаружилось что некоторые страницы он портил, причину «быстро» установить не удалось. Обновить Apache и все фильтры до последних версий (нового mod_sed, к примеру) мне не светило (ядро и либы старые в системе). В общем, остался я с mod_filter, в конфиг виртуального хоста вставил что-то вроде

    ExtFilterDefine fixtext mode=output intype=text/html \
        cmd="/opt/bin/sed 's|</body>|<script src=\"/injector.js\" type=\"text/javascript\"></script></body>|i'"
    
    ProxyRequests On
    ProxyVia On
    
    <Proxy *>
    SetOutputFilter fixtext
    </Proxy>
    

    и пользовался. Файлы правил «как обычно», через SSH/mc, или в Textastic через SFTP (у меня iPad).

    Содержание injector.js, пример:

    function injectJS(file) {
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        script.src = 'file';
        script.type = 'text/javascript';
        head.appendChild(script);
    }
    
    if (window.location.hostname == 'habrahabr.ru') {
        injectJS('filepath/mod-habrahabr.ru.js');
    }
    

    Вместе веселее


    А потом одному стало скучно. Предлагаю желающим присоединиться к тестированию и использованию.

    Сделана страница регистрации, где вы вводите свой email. От него откусывается часть до @, с этим именем создается пользователь для openssh, домашняя папка под chroot, и UserDir для Apache. На почту высылается сгенерированный пароль. В выданный shell можной зайти через SSH или SFTP, в папке htdocs лежит пример «инжектора» на JS, доступен редактор vim.

    Хост для SSH/SFTP и прокси один и тот-же.

    После успешной авторизации, прокси подключает ко всем страницам (к которым сможет) ваш собственный injector.js из htdocs, в чём собственно и смысл создания учёток. Ссылка на корень сайта, где якобы лежит injector.js, подменяется сервером на путь вида /~username/, откуда на самом деле и берутся файлы для подмены (JS/CSS).

    Адрес страницы регистрации: http:/injector.slcontent.ru/reg/.

    Хотелось бы услышать мнения относящиеся к идее как таковой, советы, отзывы по использованию.

    upd1: Чтобы проверить правильность присланной вам пары логин/пароль, проще всего зайти на страницу вида
    http://injector.slcontent.ru/~username/

    upd2: Внутри injector.js, если кто видел, есть обращение к скрипту getlink.php. У него есть параметр ts. Если ts=1, к имени файла добавляется таймштамп, что поможет избежать «залипания», к примеру, файлов стилей в кеше при частых правках.

    upd3: Внимание, логины приводятся к виду, совместимому с Linux, в моём случае: точки заменяются на подчёркивания; если первый символ — цифра, подчёркивание ставится перед цифрой; регистр приводится к нижнему. Все, у кого были в имени цифры (в начале) и большие буквы, к сожалению, не «завелись», хотя и получили письма.

    upd4: После 14 часов 29.01.2012 была недоступна страница регистрации, глупая ошибка, починил.

    upd5: Примеры того, что можно «внедрить» через этот прокси (для хабра): улучшенный навигатор по комментариям, изменения в дизайне, смена favicon, если пост перенесен в черновики или даже HabrAjax.

    upd6: При желании, можно настроить устройство ходить через прокси не на все сайты, а всего на пару, скажем. Используем для этого Web Proxy Auto Discovery Protocol. Собственно как уже писалось (возможно, не раз), цель этого протокола — рассказать, где искать файл с типом «application/x-ns-proxy-autoconfig», по-умолчанию — wpad.dat. Рассказывается это через DNS/DHCP или, что нужно в нашем случае, можно указать местоположение файла явно. В настройках прокси большинства устройств это пункт Auto c полем для URL. В поле нужно вписать
    http://injector.slcontent.ru/wpad.dat?
    со знаком вопроса в конце.

    Принцип тут такой же, как с injector.js — после авторизации выполняется редирект на версию файла в папке пользователя, т.е. всеми правилами использовать/не использовать прокси рулит сам пользователь. Пример wpad.dat (собственно, это JS с зарезервированным именем функции FindProxyForURL):

    function FindProxyForURL(url, host) {
        var proxy = "PROXY injector.slcontent.ru";
        var viaproxy = new Array(
    			    /\.ya\.ru$/,
    			    /\.yandex\.ru$/);
        for (i = 0; i < viaproxy.length; i++) {
    	if (viaproxy[i].test(host)) {
    	    return proxy;
            }
        }
        return "DIRECT";
    }
    

    Может даже получится использовать как блокер нежелательного контента (баннеров?), если сделать список с нужными хостами и указывать для них несуществующий прокси, 127.0.0.1, как часто в hosts прописывают.
    upd7: Прошли годы, и на iOS появились Content Blockers…
    Поделиться публикацией
    Комментарии 27
      +1
      Мне кажется хабракат бы не помешал :)
        +4
        Он был. Дважды. Потому и не сработал. :) Поправил.
          0
          Тоже часть текста пытались обернуть?
            0
            Угу. :)
              0
              Это хабрабаг.
        +1
        Всплыла ошибка, пользователи с точкой не заводились. Добавил кавычек в скрипт.

        Господа с точкой, давайте вас заново заведём? Только вы напишите мне в личку.
          +1
          Исправьте кодировку в скрипте рассылки.
            +1
            Поменял plain на MIME, кодировку выставил utf-8.
            +7
            Юному хакеру на заметку — как отсниффить трафик половины хабра :)
              0
              См. upd6.
              0
              Делал одно время проксю на своем VDS, которая резала рекламу по блэклисту, и эту проксю прописывал в настройках инета на планшете… но вот до идеи правки контента таким образом не додумался :) надо будет взять на заметку…
                +2
                Используй Opera Mobile, Люк.
                Есть и UserJS (настраивается, как и на декстопе, через opera:config).
                И UserCSS — my.opera.com/community/forums/topic.dml?id=1069032

                А в качестве бонуса — режим Turbo для экономии мобильного трафика.
                  0
                  Увы, на Айфоне и Айпаде нет Оперы Мобайл.
                    0
                    На айфоне с айпадом вообще мало чего есть…
                      0
                      Mini не подойдёт?
                        0
                        Нет. Настройка UserJS/CSS в Opera подразумевает, что вы можете положить нужные вам файлы куда-то в файловую систему. На Android доступно устройство SD, на iOS устройстве файловая система недоступна (без jailbreak).
                          0
                          Разработчик может сделать доступной папку Documents в приложении.
                            0
                            Конечно может. Но тут рассуждение ведётся с точки зрения конечного пользователя.
                          0
                          Mini получает данные через прокси-сервер Оперы в своём формате. Грубо говоря, уже почти нарисованную картинку и текст. Вряд ли вы сможете положить свои файлы на сервера Оперы.
                      0
                      Она мне не нравится. Не как пользователю, не как разработчику сайтов. :)
                        0
                        Это про Оперу?
                          0
                          Угу.
                          0
                          А можно подробнее, чем не нравится Opera Mobile?
                          0
                          Internal Server Error, наверно хабраэффект.
                            0
                            Не… права на файл с паролями слетели. Поправил. Спасибо!
                            0
                            Завел инжектор заново. Но как 2 года назад он почему-то не работает. Помощь мне что-ли нужна. :)
                              0
                              Заработал. Welcome, кому интересно.

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое