Pull to refresh

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

Firefox
Здравствуй %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, которая позволяет выбирать картинки для загрузки не перетаскивая их;
Tags:
Hubs:
Total votes 39: ↑36 and ↓3 +33
Views 1.4K
Comments 52
Comments Comments 52

Posts