Шосте почуття Facebook

Розширення для Chrome показує, коли хтось набирає текст


Деякі люди занадто багато часу проводять в соціальних мережах. Настільки багато, що у них виникає залежність. Один з таких — програміст Олександр Кирзенберг (Alexandre Kirszenberg), який до того ж любить копатися в нутрощах Facebook — в коді JavaScript, відповідає за користувальницький інтерфейс і комунікації.

«Пару місяців тому я задумався про маленькому статусному індикатор, який показує, коли один з ваших друзів набирає текст, — пише Олександр. — Таке маленьке розширення UI видає багато інформації про співрозмовника. Якщо індикатор кілька разів спалахує і гасне, це говорить про нерішучості. Якщо він загорівся надовго, хтось пише вам велике есе. І немає нічого гірше того болісного почуття, коли індикатор гасне і більше не загоряється».

Першим ділом Олександр вирішив знайти, надсилає чи Facebook повідомлення про те, що хтось набирає повідомлення в Facebook Messenger, навіть якщо у вас не запущено цей Facebook Messenger. Виявилося, що надсилає.

Всім френдам розсилається подія
typ
довгого опитування
/pull
. Невелике дослідження показало, що подія дійсно розсилається для кожного чату, навіть якщо одержувач не відкривав його і ніколи не отримував.

Так з'явилося розширення Facebook Sixth Sense для браузера Chrome. Воно показує прямо в браузері, коли хтось набирає повідомлення в Facebook.



Для створення цього розширення програміст використовував недокументовані Facebook API. Довелося розбиратися з кодом JavaScript, який Facebook безжально минифицирует, перетворюючи в мішанину символів.

Спочатку він з'ясував, які модулі Facebook імпортує через програмний інтерфейс системи організації модулів Asynchronous Module Definition для асинхронної завантаження (у Facebook власна реалізація AMD). Модулі і залежно визначаються стандартною функцією
__d(name, dependencies, factory)
. Є також
require
та
requireLazy
для імпорту модулів.

Найпростіше подивитися, як це працює, в консолі браузера (хоча Facebook суворо забороняє це робити). Схоже, там працюють серйозні хлопці, з ними краще не жартувати.



Але ми все-таки наважимося.



Як бачимо, Facebook завжди завантажує останню версію React — відмінною бібліотеки компонентів користувальницьких інтерфейсів. Facebook досить інтенсивно використовує React по всьому сайту. У коді Facebook більше 15 000 компонентів React (за станом на жовтень 2015 року).

У вихідному коді можна пошукати
__d(
і подивитися список модулів, доступних для імпорту. Для головної сторінки там всього 3000 модулів.

В чаті Facebook Messenger, зрозуміло, теж використовуються компоненти React. Нам потрібно перехопити нотифікації про наборі тексту. Для більш детального вивчення коду Олександр Кирзенберг рекомендує використовувати інструмент React Developer Tools.





Після установки цього розширення інструментів розробника Chrome з'являється нова вкладка React. На ній виділяємо чат.



Тут серед різних компонентів Facebook Messenger шукаємо індикатор набору тексту, він знаходиться між
<ChatTabComposerContainer />
та
<MercuryLastMessageIndicator />
.

Пошук
__d('ChatTyping
в кодовій базі React знаходить два модуля
ChatTypingIndicator.react.js
та
ChatTypingIndicators.react.js
. Це саме те, що нам потрібно, пише Кирзенберг. Він зауважує, що деякі модулі завантажуються в міру необхідності, тому що
ChatTypingIndicators.react.js
можна виявити тільки з другого разу.

Ось його код.

function() {
var k = c('MercuryThreadInformer').getForFBID(this.props.viewer)
, l = c('MercuryTypingReceiver').getForFBID(this.props.viewer);
this._subscriptions = new (c('SubscriptionsHandler'))();
this._subscriptions.addSubscriptions(
l.addRetroactiveListener(
'state-changed',
this.typingStateChanged
),
k.subscribe(
'messages-received',
this.messagesReceived
)
);
},

А саме, нас цікавить виклик
c('MercuryTypingReceiver')
.

В консолі можна подивитися, як він працює.

> MercuryTypingReceiver.getForFBID
// function (i){var j=this._getInstances();if(!j[i])j[i]=new this(i);return j[i];}
> MercuryTypingReceiver.get
// function (){return this.getForFBID(c('CurrentUser').getID());}

Для перевірки, як працює статусний індикатор, Олександр використовував додаток Messenger на власному смартфоні, щоб відправити себе на ПК відповідні події і зловити їх у консолі.

Більш докладно вивчивши код, він знайшов ще два корисних модуля
MercuryThreads
та
ShortProfiles
. Перший отримує всю інформацію про тред Messenger по його ідентифікатору, другий робить те ж саме за профілем.

Загалом, після всіх пошуків ось як виглядає остаточний код розширення для Chrome, всього 40 рядків.

function getUserId(fbid) {
return fbid.split(':')[1];
}

requireLazy(
['MercuryTypingReceiver', 'MercuryThreads', 'ShortProfiles'],
(MercuryTypingReceiver, MercuryThreads, ShortProfiles) => {

MercuryTypingReceiver
.get()
.addRetroactiveListener('state-changed', onStateChanged);

// Called every time a user starts or stops typing in a thread
function onStateChanged(state) {

// State is a dictionary that maps thread ids to the list of the
// currently typing users ids'
const threadIds = Object.keys(state);

// Walk through all threads in order to retrieve a list of all
// user ids
const userIds = threadIds.reduce(
(res, threadId) => res.concat(state[threadId].map(getUserId)),
[]
);

MercuryThreads.get().getMultiThreadMeta(threadIds, threads => {
ShortProfiles.getMulti(userIds, users => {
// Now that we've retrieved all we need the information
// about the threads and the users, we send it to the
// Chrome application to process and display it to the user.
window.postMessage({
type: 'update',
threads,
users,
state,
}, '*');
});
});

}
}

);

Непоганий такий хак, злегка розкриває нутрощі Facebook.

Вихідний код розширення опубліковано на Github.

До речі, за часовими мітками з месенджера Facebook можна навіть відстежувати режим сну своїх френдів (вихідний код).


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.