geekr icon indicating copy to clipboard operation
geekr copied to clipboard

Add user support

Open jarvis394 opened this issue 3 years ago • 24 comments

Need a following codes for sending user request:

Cookie: _csrf=value1
csrf-token: value2

Create a page where user can paste these values from a script, that is being executed on the main habr page.

jarvis394 avatar Nov 01 '20 18:11 jarvis394

Да, авторизации действительно не хватает для комментарией и поиска по своей ленте

sprainbrains avatar Nov 02 '20 19:11 sprainbrains

Login habr:

  1. Заходим по ссылке логина, где мы хотим авторизоваться https://habr.com/ru/auth/login/ Браузер отправляет GET https://habr.com/ru/auth/login/ HTTP/1.1 Получаем ответ:
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Документ переехал!</title>
</head>
<body>
  <a href="https%3A%2F%2Faccount.habr.com%2Flogin%2F%3Fstate%3D322c8679bd08d901ceeb7f0fd47fc551%26consumer%3Dhabr%26hl%3Dru_RU">https://account.habr.com/login/?state=322c8679bd08d901ceeb7f0fd47fc551&amp;consumer=habr&amp;hl=ru_RU</a>
</body>
</html>

Мы видим, что он генерирует ссылку с параметрами state, consumer. Нам нужен state Если перейти по https://account.habr.com/login/?state=322c8679bd08d901ceeb7f0fd47fc551&consumer=habr&hl=ru_RU то будет просто форма логина.

  1. Теперь я попытаюсь в эту web форму ввести свой логин пароль Передаем пост запрос с известными параметрами POST https://account.habr.com/ajax/login/ HTTP/1.1 http-referer https://account.habr.com/login/?state=322c8679bd08d901ceeb7f0fd47fc551&consumer=habr&hl=ru_RU
state:                322c8679bd08d901ceeb7f0fd47fc551
consumer:             habr
email:                [email protected]
password:             MyLongPassword123
captcha:              
g-recaptcha-response: 
captcha_type:         recaptcha

Получаем респонс со следующим содержимым:

window.location.href = 'https://habr.com/ac/entrance/?token=a122f063b00278fcd27f482616316513&state=322c8679bd08d901ceeb7f0fd47fc551&time=1604393689&sign=2bfe68e12b8ef4aadfe3649000fda975&utm_nooverride=1';

Если перейти по этой ссылке, то возвращается html документ:

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Документ переехал!</title>
</head>
<body>
  <a href="https%3A%2F%2Fhabr.com%2Fru%2F">https://habr.com/ru/</a>
</body>
</html>

Ну вот мы получили токен. token=a122f063b00278fcd27f482616316513

LencoDigitexer avatar Nov 03 '20 09:11 LencoDigitexer

Комментарии к посту

POST https://habr.com/json/comment/ HTTP/1.1 http-referer https://habr.com/ru/post/526068/

ts:         1604393729
tt:         2
ti:         526068
comment_id: 0
parent_id:  0
text:       Будем помогать проекту
action:     add

Ответ в виде html файла с JavaScript скриптами

LencoDigitexer avatar Nov 03 '20 09:11 LencoDigitexer

Но, допустим, я хочу изменить свою специальность - захожу в настройки аккаунта https://habr.com/ru/auth/settings/profile/ И меняю специальность, допустим, на python разработчик

POST https://habr.com/json/settings/profile/ HTTP/1.1

Host: habr.com
Connection: keep-alive
Content-Length: 92
Accept: application/json, text/plain, /
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36 Edg/86.0.622.58
Content-Type: application/x-www-form-urlencoded
Origin: https://habr.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://habr.com/ru/auth/settings/profile/
Accept-Encoding: gzip, deflate, br
Accept-Language: ru
Cookie: habrsession_id=habrsession_id_e7e33de3f0f541108140068a6d5c9cf0; hl=ru; fl=ru; _ga=GA1.2.1205135727.1604395784; _gid=GA1.2.757514714.1604395784; _ym_uid=16043957851020971966; _ym_d=1604395785; _ym_isad=2; _ym_visorc=w; PHPSESSID=5d87e9r2ivnqaek0oe4p8iq8ru; hsec_id=342d6cf32b4f55666f7a1b774bfcc84b; feed_flow=top; split201901=B; ab_test_vacancies_block_group=A; neuro-habr=ab92f052-ff7e-45a6-a005-fe1812dba9f1; _ym_visorc_24049213=b
sex:        0
specializm: Python разработчик

По сути, всё работает через куки

LencoDigitexer avatar Nov 03 '20 09:11 LencoDigitexer

Я пользуюсь endpoint'ом m.habr.com/kek/v{version} для api запросов и там всё по-другому. Но тогда для юзера можно использовать десктопный habr.com/json, чтобы использовать только один токен.

Спасибо, что подсказали!

jarvis394 avatar Nov 03 '20 14:11 jarvis394

@LencoDigitexer

Ну вот мы получили токен.

А как его использовать то? Ни token, ни sign параметры нигде не появляются на клиенте в запросах. Есть PHPSESSID, habrsession_id, hsec_id и все они не похожи на те значения, которые выдаёт habr.com/ac/entrance

jarvis394 avatar Nov 03 '20 19:11 jarvis394

Да, этот токен не очень важен. Прости за мусорное расследование, но я нашел новое. Оно основано на анализе опесорсного приложение хабра https://github.com/Makentoshe/Habrachan

Итак, авторизация.

POST https://habr.com/auth/o/access-token HTTP/1.1

Сервисные данные браузера

client: 85cab69095196f3.89453480
apiKey: 173984950848a2d27c0cc1c76ccf3d6d3dc8255b
Content-Type: application/x-www-form-urlencoded
Content-Length: 161
Host: habr.com
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.1.0

Тело POST запроса

email:         [email protected]
password:      MyLongPassword123
client_secret: 41ce71d623e04eab2cb8c00cf36bc14ec3aaf6d3
client_id:     85cab69095196f3.89453480
grant_type:    password

Ответ сервера:

Server: QRATOR
Date: Wed, 04 Nov 2020 15:34:46 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=15
Vary: Accept-Encoding
Access-Control-Allow-Origin: *
X-Frame-Options: SAMEORIGIN
P3P: CP="CAO DSP COR CURa ADMa DEVa PSAa PSDa IVAi IVDi CONi OUR OTRi IND PHY ONL UNI FIN COM NAV INT DEM STA"
X-Content-Type-Options: nosniff
Content-Encoding: gzip
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Public-Key-Pins: pin-sha256="jWWta3ma1DSx8lFr6uv04x6sSRmK5X4Z0ivIL7+qKLM="; pin-sha256="Efde6ZPsmxzZkludmzwnp0QJhZ1mSwHrhDxczbpZcmM="; pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; pin-sha256="kUh5F9diW5KlrhQ+nEKTIVFWVZuNbVqkKtm+KOGPXCE="; max-age=15552000
X-Proxy-Upstream: habrcom-engine
{
    "access_token": "90f1c66b314a095a14f259aa4ac40f3d6d59babf",
    "server_time": "2020-11-04T18:34:45+03:00"
}

Теперь на основе этих данных попробуем получить данные обо мне

GET https://habr.com/api/v1/users/me HTTP/1.1

Сервисные данные браузера

client: 85cab69095196f3.89453480
token: 90f1c66b314a095a14f259aa4ac40f3d6d59babf
Host: habr.com
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.1.0

Ответ сервера:

{
    "data": {
        "avatar": "https://habr.com/images/avatars/stub-user-middle.gif",
        "badges": [
            {
                "alias": "habred",
                "description": "Пользователь с кармой >0",
                "id": 1,
                "is_disabled": false,
                "is_removable": false,
                "title": "Захабренный",
                "url": null
            }
        ],
        "common_tags": [],
        "contacts": [],
        "counters": {
            "comments": 7,
            "favorites": 9,
            "followed": 1,
            "followers": 0,
            "posts": 0
        },
        "fullname": null,
        "geo": {
            "city": null,
            "country": null,
            "region": null
        },
        "id": 2279184,
        "is_can_vote": false,
        "is_rc": true,
        "is_readonly": false,
        "is_subscribed": false,
        "login": "LencoDigitexer",
        "path": "/users/lencodigitexer/",
        "rating": 0,
        "rating_position": 0,
        "score": 1,
        "sex": 0,
        "specializm": "Python разработчик",
        "time_registered": "2020-02-07T18:04:28+03:00"
    },
    "server_time": "2020-11-04T18:34:46+03:00"
}

LencoDigitexer avatar Nov 04 '20 15:11 LencoDigitexer

Вот здесь описан api Хабра

https://github.com/Perkovec/HabrApi/blob/96413ad10c28b5b4432aefb82fc70b63b519c3b2/README.md

LencoDigitexer avatar Nov 04 '20 15:11 LencoDigitexer

Вот это уже круто!

Я же нашёл значения csrf-token, _csrf и connect_sid на фронте:

  1. csrf-token берётся из
    document.querySelector('meta[name="csrf-token"]').content
    
  2. _csrf и connect_sid берутся из куки. Вот только connect_sid через скрипт не получишь, там стоит HttpOnly флаг.

Можно просить пользователей заходить в DevTools и копировать значения в приложение, но мне ой как кажется, что это дико неудобно. Ваш метод гораздо легче.

Единственный вопрос - как брать client_id? Я нашёл, что https://m.habr.com/kek/v1/auth/habrahabr/?back=/ru/all/&hl=ru редиректит на https://habr.com/ru/auth/o/login/, где есть в параметрах этот client_id, но можно ли его по-другому вытащить?

UPD: смог получить те же данные из users/me, подставляя как свой client_id, так и ваш. Похоже, серверу вообще плевать, что там стоит.

jarvis394 avatar Nov 04 '20 17:11 jarvis394

csrf-token берется отсюда. Вот...

https://m.habr.com/ru/sasasa/

Найти строку

<meta name="csrf-token" content="ccYo6XIK-Iv9i-0Nq7pTdx0YfjT0SzdV6-IA">

Мне кажется, client_id нужно получить, регистрируя своё приложение, так ведь?

LencoDigitexer avatar Nov 04 '20 18:11 LencoDigitexer

От https://m.habr.com/kek/v1/auth/habrahabr идёт редирект на https://habr.com/ru/auth/o/login с такими параметрами, как state и client_id. Я бы брал отсюда client_id, но axios как-то хреново хандлит редиректы, поэтому походу будет просто легче взять какой-нибудь client_id, главное чтобы работало.

jarvis394 avatar Nov 04 '20 18:11 jarvis394

Мне кажется, client_id нужно получить, регистрируя своё приложение, так ведь?

image

И кто мне, собственно, разрешит такое делать? Для того, чтобы приложение одобрили, нужна ясная причина, а тут я просто хочу абузить их апи.

jarvis394 avatar Nov 04 '20 18:11 jarvis394

Ну раз это полулегально, то пусть client_id=85cab69095196f3.89453480 будет от HabraChan. А так, Вашу новость на хабре оценили и почему бы не попытаться достучаться до тех поддержки?

LencoDigitexer avatar Nov 04 '20 19:11 LencoDigitexer

Уже написал, жду ответа.

Есть на примете ещё доки по API хабра для приложений? Потому что одних комментариев будет мало) К тому же, нигде эти пути не найти ни на мобильном, ни на десктопном сайте.

jarvis394 avatar Nov 04 '20 21:11 jarvis394

Думаю, тебе скинут документацию по api хабра. А так, вот несколько описаний api, что я смог найти: https://github.com/Perkovec/HabrApi https://github.com/Makentoshe/Habrachan/wiki

LencoDigitexer avatar Nov 04 '20 21:11 LencoDigitexer

Здравствуйте! К сожалению, в данный момент доступ к нашему API не предоставляется. Мы планируем возобновить предоставление доступа после того как закончим доработку публичного API, но каких-либо точных дат у нас пока нет, т.к. в данный момент мы заняты решением других приоритетных задач.

Ожидаемо.

jarvis394 avatar Nov 05 '20 06:11 jarvis394

О, привет всем! Видел мой репо пинганули тут (чисто случайно). Какие именно описания вам нужны? Описания на вики там немного подтухли, бтв.

Если еще актуально, офк

Makentoshe avatar May 16 '21 11:05 Makentoshe

Это победа!

Мне удалось сделать авторизацию через сайт мобильного API (habr.com/kek/v1/auth)!

@Makentoshe , сегодня выложу код на гитхаб, если надо. Тогда ты сможешь отказаться от поддержки старой версии API.

Единственный минус - все запросы для авторизации нужно делать с сервера (в том числе и получать csrf токен)

jarvis394 avatar Jul 25 '21 11:07 jarvis394

@jarvis394 Красиво, спасибо. У меня тоже кое какие наработки есть +- рабочие, но на андройд они ложатся не нативно, а через WebView(встроенный браузер с движком), т.к. для нативной реализации нужно проходить гуглокапчу, а без доступа к приватному ключу капчи нативно это по нормальному не сделать (через гугол либу для этого).

Makentoshe avatar Jul 25 '21 12:07 Makentoshe

а без доступа к приватному ключу капчи нативно это по нормальному не сделать

Т.е. гкапчу, такую же, как на сайте account.habr.com, можно сделать (скорее скопировать) в браузере? Когда я делал авторизацию, я вообще про капчу забыл :p

Когда при тестах вылезала капча, я логинился на основном сайте и капча уходила.

jarvis394 avatar Jul 25 '21 12:07 jarvis394

@jarvis394 ага, она только в браузере и работает. Юзается v2reCAPTCHA. Можно с Fiddler'ом или Wireshark'ом побуриться, я там находил и апи ключ и прочее, как это у них работает на фронте. Я особо не web-developer, поэтому сильно сказать не могу, что там конкретно есть, и насколько полезно

Для андройда там нужно свой ключ отдельный генерировать и к тому же при генерации указывать application package приложения, ну т.е. вообще не вариант. Я в андройде генерировал уже готовенькую ссылку со всеми свистелками, показывал на webview дефолтную форму логина, а потом перехватывал response и вытаскивал нужные куки

Makentoshe avatar Jul 25 '21 13:07 Makentoshe

сегодня выложу код на гитхаб

https://github.com/jarvis394/habra-auth/blob/main/src/index.ts

jarvis394 avatar Jul 25 '21 14:07 jarvis394

сегодня выложу код на гитхаб

https://github.com/jarvis394/habra-auth/blob/main/src/index.ts

Ну так то да, если в пароле не ошибаться, то капча вылезать не будет и все будет ок. Если хоть раз ошибиться, дальше сервер будет требовать g-recaptcha-response. А еще он может ее сбросить, если время истекло, там вроде секунд 30-60 примено, точно не помню, и надо будет новую запрашивать

Makentoshe avatar Jul 25 '21 17:07 Makentoshe