My Yandex.Fotki Uploader (Myf) — начало открытого тестирования

    Здравствуй %USERNAME%. Прошло 10 суток с тех пор, как была опубликована статья про плагин, который загружает фотографии путем drag&drop на textarea графических файлов.

    Описание для тех, кто не в курсе предыдущего поста:
    Представим ситуацию — необходимо в ЖЖ (LiveJournal) или на форум разместить десяток фотографий. Если Вы используете Яндекс.Фотки для размещения фотографий в сети, то этот плагин Вам очень поможет. Перетащите на текстовое поле, где пишете сообщение, фотографии и дождитесь загрузки и появления html/bbcode тегов со ссылками на фотографии.



    Сложности


    Самой большой сложностью для меня было решение вот этой задачи:

    В настоящий момент сервис выдачи авторизационных токенов поддерживает только нестандартный вариант RSA шифровании, поэтому от клиентов требуется использование специальной библиотеки шифрации. Исходные тексты варианта библиотеки для языка С/С++ доступны по адресу download.yandex.ru/api-fotki/c-yamrsa.tar.gz.


    Расширение для FireFox пишется на Javascript. Добавлять в расширение отдельную программу encrypt под кажду ОС (Windows/Unix/MacOS) — очень не хотелось.
    В процессе общения с людьми на хабре — меня нашел lomik, который перенес основную логику Yandex RSA на Python язык.

    Вот этот скрипт. Автор: lomik

    #-*- coding:utf-8 -*-<br/>
    <br/>
    import sys, copy<br/>

    <br/>
    if __name__ == '__main__':<br/>
      if len(sys.argv) != 3 : print "usage: python %s <public-key> <text>" % sys.argv[0]; sys.exit()<br/>

      NSTR,ESTR = sys.argv[1].split("#")<br/>
      DATA_ARR = [ord(x) for x in sys.argv[2]]<br/>
      N,E,STEP_SIZE = int(NSTR,16),int(ESTR,16), len(NSTR)/2-1<br/>

      <br/>
      prev_crypted = [0]*STEP_SIZE<br/>
      <br/>
      hex_out = ""<br/>
      for i in range(0,(len(DATA_ARR)-1)/STEP_SIZE+1):<br/>
        tmp = DATA_ARR[i*STEP_SIZE:(i+1)*STEP_SIZE]<br/>
        tmp = [tmp[i] ^ prev_crypted[i] for i in range(0,len(tmp))]<br/>

        tmp.reverse()<br/>
        plain = 0<br/>
        for x in range(0,len(tmp)): plain+= tmp[x]*pow(256, x, N)<br/>
        hex_result = "%x" % pow(plain,E,N)<br/>
        hex_result = "".join(['0']*( len(NSTR)- len(hex_result))) + hex_result<br/>

    <br/>
        for x in range(0,min(len(hex_result),len(prev_crypted)*2),2):<br/>
          prev_crypted[x/2] = int(hex_result[x:x+2],16)<br/>
          <br/>
        hex_out += ("0" if len(tmp) < 16 else "") + ("%x" % len(tmp)) + "00" # current size<br/>

        ks = len(NSTR)/2<br/>
        hex_out += ("0" if ks < 16 else "") + ("%x" % ks) + "00" # key size<br/>

        hex_out += hex_result<br/>
    <br/>
      print hex_out.decode("hex").encode("base64").replace("\n","")
    <br/>
    <br/>


    У меня не было особо выбора, но я решился портировать Python скрипт на JS :-)

    Второй проблемой стало ограничение JavaScript в плане работы с большими числами (BigInt), что приводит к потере точности вычислений и как следствие ошибочные результаты. Мне помогла готовая библиотека функций BigInt.js.

    В качестве вспомогательных функций использовал:


    В итоге, получилась такая полезная функция:

    function encrypt_yarsa(key, toenc)
    {
      /* Encode string like RSA
       * Ported to JS by Artur Khasanov
       * EMail: artur[at]hasanov.ru
       * Website: hasanov.ru
       * JS source: wiki.hasanov.ru/software/yandex-rsa
       * Ported from Python script written by lomik.habrahabr.ru
       */
      var DATA_ARR = [];
      var NSTR = key.split('#')[0];
      var ESTR = key.split('#')[1];
      var N = bigInt2str(str2bigInt(NSTR, 16,0),10);
      var E = bigInt2str(str2bigInt(ESTR, 16,0),10);
      var STEP_SIZE = NSTR.length/2-1;
      var prev_crypted = new Array(STEP_SIZE);
      var hex_out = "";
      var plain = new String();
      for(i=0;i<toenc.length;i++)DATA_ARR[i] = ord(toenc.substr(i,1));
      for(i=0;i<parseInt((DATA_ARR.length-1)/STEP_SIZE)+1;i++){
        tmp = DATA_ARR.slice(i*STEP_SIZE, (i+1)*STEP_SIZE);
        for(j=0;j<tmp.length;j++)tmp[j] = (tmp[j] ^ prev_crypted[j]);
        tmp.reverse();
        var plain = int2bigInt(0,0);
        for(x=0;x<tmp.length;x++){
          pow = powMod(int2bigInt(256,0), int2bigInt(x,0), N);
          pow_mult = mult(pow, int2bigInt(tmp[x],0));
          plain = add(plain, pow_mult);
        }
        plain_pow = powMod(plain, str2bigInt(E,10,0), str2bigInt(N,10,0));
        plain_pow_str = bigInt2str(plain_pow, 16);
        hex_result = new Array((NSTR.length - plain_pow_str.length) + 1).join('0') + plain_pow_str;
        min_x = Math.min(hex_result.length, prev_crypted.length*2);
        for(x=0;x<min_x;x=x+2)prev_crypted[x/2] = parseInt("0x"+hex_result.substr(x, 2));    
        if(tmp.length < 16) hex_out+="00";
        hex_out += tmp.length.toString(16).toUpperCase() + "00";
        ks = NSTR.length/2;
        if(ks<16) hex_out += "0";
        hex_out += ks.toString(16).toUpperCase() + "00";
        hex_out += hex_result;

      }
      return base64Encode(hexDecode(hex_out.toLowerCase())).replace(/[\n\r\t]/g, "");
    }


    * This source code was highlighted with Source Code Highlighter.


    Интегрировал ее в расширение для Firefox и получилась конфетка.

    Результаты


    Каждый день по 30-40 минут изучал XUL, особенности JS для работы с настройками и т.д. И теперь могу смело представить всем:

    Окно настроек:


    Статус бар:



    Установить/Скачать Плагин: Myf на addons.mozilla.org (главный и единственный источник распространения плагина)

    *Сейчас этот плагин лежим в песочнице на addons.mozilla.org и что бы он стал публичным мне нужны там комментарии и замечания для доработки. Статус в песочнице не дает плагину обновляться через автоматическое обновлении. Буду стараться вывести плагин из песочницы как можно быстрее.

    Планы на будущее


    • Автоматический выбор шаблона в зависимости от ссылки (по домену или по имени скрипта);
    • Выбор альбома по умолчанию;
    • Проверка введенного логина (отбрасывать собаку и все, что после);
    • Придумать иконку для плагина;
    • Добавить возможность отмены запущенной загрузки;
    • Определение ширины и высоты картинки + прописывание их в атрибутах;
    • Написать мини инструкцию;
    • Локализовать на русский и английский язык;
    • Кнопка рядом с каждой Textarea, которая позволяет выбирать картинки для загрузки не перетаскивая их;
    Поделиться публикацией

    Комментарии 52

      +2
      Увидев заголовок, сначала подумал, что это блог linux. Сделано всё Ъ, unix way.
      Подредактируй текст, есть небольшое количество ошибок, сам легко найдёшь при перечитывании.
      Пойду тестировать и комментировать.
        0
        Сделано всё Ъ, unix way.

        Это как? =)

        Хорошо. сейчас перечитаю.
          +1
          Unix way понятие комплексное. Платформонезависимость — Ъ.
            0
            Очень надеюсь, что под Юникс будет работать =)

            Признаюсть честно — под юниксами не тестировал, но Яваскрипт должен быть везде одинаковый :-)
        +1
        Боже, 5 минут ломал голову почему не могу получить Token.
        Уже почти плюнул, и тут заметил на скриншоте, что логин указан без @yandex.ru )))) Будьте внимательны.
        А так спасибо… работает на 5+
          0
          +1 Приму к сведению принудительно удалять @yandex.ru/@ya.ru :-)
          +1
          Спасибо! Первую статью не заметил, т.к. не вышла на главную. Народ, ведь это реально ОЧЕНЬ удобная вещь. Непонятно, почему так мало плюсов автору. Неужели никого не напрягает загружать картинки для своих статей через веб-интерфейс Пикасы или Яндекс.Фоток?
            –2
            Ваша мысль двояка. Конечно, плюсы это хорошо, но смысла от них не много. Намного важнее то, что целевая аудитория все равно есть у этого поста. А выносить на главную страницу безсмысленно, т.к. есть ссылка на тематические блоги.

            Темболее, этот плагин еще не закончен. Много нужно в нем доделать, реинжиниринг кода провести и сделать мультиязычный интерфейс.
            0
            Для PHP никто этот Yandex RSA не писал? Или придётся самому?
              0
              Для PHP там намного все проще =) Думаю, это не вызовет у Вас затруднений.
                0
                В каком месте проще? RSA точно так же приходится портировать.
                Уже часов 5 бьюсь над этой задачей.
                Надеюсь разработчикам API Яндекс.Фотки сейчас икается. Сильно.
                Если вы знаете готовое решение — поделитесь пожалуйста.
                  0
                  во первых в php уже все функции встроенные (ord, base64 и т.д, в отличие от яваскрипта.).

                    0
                    А работа с bigInt? Я использу библиотеку из пира для этого.
                    Можно вас немножко поданимать?
                    Очень хочется написать класс, который позволит работать с Яндекс.Фотки… но пока с rsa так и не разобрался.
                +2
                Слижи с моего кода или JS-а. Там все предельно просто — не нужно даже вдумываться.
                +1
                Покопался, посмотрел что получилось. Список пожеланий и уточнений.

                1. Ограничение на Firefox 3.6+ чем-нить технически обосновано?

                2. Настройки должны быть доступны тут тоже
                clip2net.com/clip/m12120/1265812477-clip-17kb.png

                3. Реализуй таки вставку картинки через пункт контекстного меню textarea. Drag&drop прошел мимо меня :)
                Желательно вставлять туда, где у меня курсор был — не удобно, когда вставляет в конец, а не в нужное место.

                4. При чтении кода нашел багу:
                Если на странице textarea появится после DOMContentLoaded (например ajax-ом), тогда вставить туда нельзя будет.
                Исправить просто — вешать listener ondrop на document или body и уже в обработчике события смотреть кто собственно поймал.

                5. Было бы хорошо иметь возможность не запоминать пароль от Яндекса. Например, чтобы запоминало логин, а пароль запоминало только, если галочка поставлена. Если пароль не запомнен, тогда при первой загрузке в пределах текущей сессии спрашивать.
                  0
                  Эх. =) Надо было бы не просить лезть в код =) Там ахтунг маленько. :-)

                  1. В версии 3.6+ немного по новому начали обрабатываться drag&drop файлы. Добавлять разветвленную логику очень не хочется, ибо другие элементы дописать нужно.

                  2. Там будет :-) Одну строчку прописать и все :-)

                  3. Контекстное меню не изучал, поэтому и не добавлен функционал :-)

                  4. Спасибо. буду с listener разбираться =)

                  5. Пароль от яндекса не сохраняется. Хранится логин и токен :-) При закрытиии окна с настройками пароль просто исчезает =)
                    +1
                    Ну про ахтунг ты сам сказал :)

                    За пункт 5 извиняюсь — невнимательно смотрел.
                      0
                      пофиксил 4-й пункт.

                      по поводу вставки текста в конкретную позицию — придется переключать textarea в режим readonly до конца загрузки всех фоток. Иначе человек во время загрузки фоток напишет еще кучу буков и в итоге код картинок вставится совсем не туда =)
                        0
                        Ну можно запоминать позицию сначала. Я скорее вставлю картинку и пойду писать дальше. Хотя это уже по твоему желанию. Я все равно не потенциальный пользователь (в блоги не пишу, из сервисов яндекса использую только деньги и пробки) — просто интересно потыкать :)
                          +1
                          Вообще есть идея посмотреть что у тебя получится в итоге и сделать тоже самое для личного использования, но с пикасой )
                            0
                            Для пикасы есть загружалка в яндекс фотки =)
                            habrahabr.ru/blogs/yandex/27445/

                            чуть доработать и будет хтмл код для картинок выдавать и в буфер обмена копировать =)
                            +2
                            Во. Придумал совсем тупой алгоритм для вставки в нужную позицию:

                            Когда начинаем грузить картинки ставим в текст арию на текущую позицию какую-нить метку вроде #uploading#. Пользователь дальше делает, что хочет не стирая метку. Как картинки загрузились — меняем метку на код.
                              0
                              ага, если пользователь не решит удалить эту метку =))))

                              и еще плохо представляю, как работает моей плагин с визуальными редакторами.
                        0
                        2-й пункт тогда если можно вынести опционально, мне удобно как есть, чтоб в конец ссылка падала.
                          0
                          Да, естественно =)
                      0
                      Код бы впорядок привели, а то нечитабельно.
                        0
                        Чем Вам код функции encrypt_yarsa не нравится? Очень даже читабельно.
                        А реинжиниринг остального кода будет чуть позже.

                        Основная моя цель была:
                        — показать работающую функцию encrypt_yarsa
                        — показать плагин (использующий функцию encrypt_yarsa), который в процессе разработки.
                          0
                          Все if'ы и for'ы в строчку лепите хотя бы
                            0
                            Если внутри if или for все го лишь одна операция, то зачем на две строки растягивать?
                              –1
                              Сразу видно где условие, а где операция.
                        0
                        Ждал, актуально :] Теперь сам пройдусь в плане оформления.

                        Это ужасно, банальная иконка «ни о чем» и не нужная надпись:
                        image

                        Так, может выглядеть гораздо лучше:
                        nado.png

                        Так это дело может выглядеть, если оно не работает:
                        ne_aktiv.png

                        Так же не совсем понятно, зачем и кому нужна строка о процентах загрузки имаги, лишь увеличивает и вводит в непонятки, вполне достаточно сколько загрузили, сколько осталось.

                        Так же вполне уместным будет, чтоб данная надпись исчезала через некоторое время сама, а не висела постоянно:
                        image

                        Ну и конечно очень не хватает выбора папки, куда мы будем загружать картинки.
                          0
                          откуда такую иконку птичку взять? =)
                            0
                            Вырезать с сайта Я.Ф или напишите какого размера и формата надо в личку, посмотрим.
                              0
                              Минимизировал занимаемое место :-)
                              Щас буду картинки придумывать, а то яндекс разозлится за прямое копирование его картинок =)
                                0
                                Не думаю, у вас бесплатное приложение работающее с их сервисом, вы это не скрываете, исходные коды. На что им злиться?
                                Хотя если уж очень хочется, при аплоаде вполне удобоваримая иконка, и висит она не долго. А так можно использовать цветную букву Ф, при не активности серую, а что :]
                                  0
                                  Будет время отпишитесь о новой версии.

                                  Но вот юзабилити сложно продумать. Думаю нужно отказаться от понятия «Токен» и писать что пароль подошел, но с другой стороны могут подумать, что плагин пароль хранит в открытом виде =)
                                    0
                                    Они теперь так смотрят на друг-друга :]
                                    image

                                    Стало заметно лучше. В момент аплоада можно писать не «Up и колличество картинок», а просто нормально «Upload и колличество картинок». Все равно эта надпись теперь сразу по окончанию исчезает, а пользователя Up/вверх может ввести в заблуждение.

                                    Хотите отказаться в сторону юзабилити от сложных слов. Замените токен на временный ключ или вроде удачной временной аутентификации. Укажите внизу окошка не большими буквами но видимыми, что пароль никуда не уходит и происходит шифрование.

                                    В настройках справочный раздел «Macros», можно заменить на кнопочки радиобатон или чекбоксы. Чтоб не вписывать значения нужные самаму, не менять, а выбирать наглядно.

                                    Да и еще, очень досадная для меня новость, ваше дополнение блокирует одно из моих любимых дополнений, без которых я не представляю себе лисичку.
                                      0
                                      Up — пофиксил.

                                      Да, в планах как-то упростить понимание ввода логина и пароля.

                                      Пойду драгдроп дополнение ковырять. не ставится оно на 3.6
                                        0
                                        Отключите совместимость. С аплоадером он перестает работать, стоит аплоадер отключить и все отлично.
                                          0
                                          Отключить совместимость что-то не получилось. Пришлось править плагин.

                                          В версии 0.5.20100211.2 исправил совместимость с плагинами, которые используют DragDdrop
                                            0
                                            Зальете ее в репозиторий чтоб попробовать?
                                            0
                                            Немного переделал нумерацию версий.

                                            в версии 0.5.3 исправлена совместимость.

                                            https://addons.mozilla.org/ru/firefox/addon/75488/

                                            Одна из приоритетных задач — найти проблему, когда процесс загрузки файла не идет, а написано 0/1 и файл не отправляется.

                                            Еще проблема с логином, в котором используется знак «точка».
                                              0
                                              Дополнение заработало, спасибо.
                                              Надпись красным смотрится не много грубовато и сильно привлекает внимание, но наверно на первое время так лучше, пока ваше дополнение не раскручено. Я бы к примеру вряд ли доверил свой пароль не известному, экспериментальному дополнению.

                                              Одна из приоритетных задач — найти проблему, когда процесс загрузки файла не идет, а написано 0/1 и файл не отправляется.

                                              Так было всего один раз, когда только установил и попробовал загрузить первую картинку, пришлось перезапускать браузер. Больше такого пока не было.
                                                0
                                                По поводу загрузки. Дело не в ошибке плагина, а в том, что возможно яндексу загружается что-то с ошибкой или яндекс ответ какой-то нестандартный возвращает. Это надо исправить, т.к. иначе нужно браузер перезапускать, пока не добавлена функция отмены загрузки.
                            0
                            а можете в двух словах сказать в чем заключается нестандартность RSA у Яндекса, просто интересно
                              +2
                              В двух словах — практически всем :)
                              Добавлена хитрая зависимость шифрования очередного куска от результата шифрования предыдущего. Все куски перед шифрованием побайтно разворачиваются. В результирующем шифр-тексте добавлены байты указывающие длину куска и тд. Короче кучка мелких танцев с бубном вокруг стандартной операции m^e mod n
                              0
                              Ваш бы функционал, да в Яндекс бар добавить — вот что было бы совсем замечательно) А вообще, спасибо автору! С нетерпением жду когда появится контекстное меню)
                                0
                                А возможно сделать получение автоматом пароль из яндекс.бара — если залогинен
                                  0
                                  Так делать нельзя. это не правильно, даже если яндекс бар хранит пароль. Вдруг они что-то изменят и в итоге мой плагин не будет работать как нужно. Мой плагин не должен зависеть от других плагинов и вмешиваться в их функциональность.
                                  0
                                  encrypt_yarsa требует ф-ю ord.
                                  Можно эту использовать.
                                  function ord(string) {
                                  // kevin.vanzonneveld.net
                                  // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
                                  // + bugfixed by: Onno Marsman
                                  // + improved by: Brett Zamir (http://brett-zamir.me)
                                  // * example 1: ord('K');
                                  // * returns 1: 75
                                  // * example 2: ord('\uD800\uDC00'); // surrogate pair to create a single Unicode character
                                  // * returns 2: 65536

                                  var str = string + '';

                                  var code = str.charCodeAt(0);
                                  if (0xD800 <= code && code <= 0xDBFF) { // High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters)
                                  var hi = code;
                                  if (str.length === 1) {
                                  return code; // This is just a high surrogate with no following low surrogate, so we return its value;
                                  // we could also throw an error as it is not a complete character, but someone may want to know
                                  }
                                  var low = str.charCodeAt(1);
                                  if (!low) {

                                  }
                                  return ((hi — 0xD800) * 0x400) + (low — 0xDC00) + 0x10000;
                                  }
                                  if (0xDC00 <= code && code <= 0xDFFF) { // Low surrogate
                                  return code; // This is just a low surrogate with no preceding high surrogate, so we return its value;
                                  // we could also throw an error as it is not a complete character, but someone may want to know
                                  }
                                  return code;
                                  }


                                  Буду благодарен, если кто то поделится портом на php.
                                  Я, честно говоря, уже тихо ненавижу эту ф-ю.
                                  Особенно из за работы с big Int
                                    +1
                                    Это мой вариант с костылем =)

                                    function ord( string ) { // Return ASCII value of character
                                    code = string.charCodeAt(0);
                                    if(code>900)code=code-848; // Может и не 900, но так работает точно.
                                    return code;
                                    }
                                      0
                                      Здорово. Спасибо. Я просто пытался запустить и функции ord yе обнаружил. Вот и решил запостить — вдруг кому то будет полезно, раз в топике нету.

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

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