08.03.2021, 17:19
|
Интересующийся
|
|
Регистрация: 17.02.2021
Сообщений: 27
|
|
Надо чтото вроде
xhr.setRequestHeader("X-CSRFToken", csrftoken);
но где взять этот csrftoken ?
С другой стороны, если внешний сайт мне посыоает данные, csrftoken уже есть где-то
|
|
08.03.2021, 17:36
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,744
|
|
Я думаю не получится считать файл, если страница берется с локального компьютера используя XMLHttpRequest или fetch.
Там идет проверка протоколов по которым получена страница. А если она локальная (from origin 'null'), то у нее нет протокола и он никогда не будет действительным и подходящим .
То, что она считывается браузером при указании в адресной строке - это совсем другое. Там таких проверок нет. Также как и при считывание с помощью <script>
|
|
08.03.2021, 19:33
|
Интересующийся
|
|
Регистрация: 17.02.2021
Сообщений: 27
|
|
Спасибо за ответ. Он укрепил мою уверенность что я рою в верном направлении
В итоге нарыл пакет на питоне для соединения с гарминовским сайтом и закачки файлов - т.е. пакет делает то что мне надо. Для закачки он использует тот же URL
https://github.com/petergardfjall/garminexport
при запуске пакета сначала идет авторизация, потом там есть код типа
def _get_csrf_token(self):
"""Retrieves a Cross-Site Request Forgery (CSRF) token from Garmin's login
page. The token is passed along in the login form for increased
security."""
log.info("fetching CSRF token ...")
resp = self.session.get(SSO_LOGIN_URL, params=self._auth_params())
if resp.status_code != 200:
raise ValueError("auth failure: could not load {}".format(SSO_LOGIN_URL))
# extract CSRF token
csrf_token = re.search(r'<input type="hidden" name="_csrf" value="(\w+)"',
resp.content.decode('utf-8'))
if not csrf_token:
raise ValueError("auth failure: no CSRF token in {}".format(SSO_LOGIN_URL))
return csrf_token.group(1)
|
|
09.03.2021, 17:06
|
Интересующийся
|
|
Регистрация: 17.02.2021
Сообщений: 27
|
|
Питон делает из своей консоли для авторизации на внешнем сайте Гармине так
headers = {'origin': 'https://sso.garmin.com'}
и там все работает
Если я имитирую это поведение в JS с XMLHttpRequest
xhr.setRequestHeader('Origin', 'https://sso.garmin.com');
то получаю
Refused to set unsafe header Origin
Пишут что подменить заголовоr мешает броузер (хром). Незадача
Но есть еще один пакет для работы с Гармином на JS, в нем для авторизации используется axios вместо XMLHttpRequest и этот пакет работает из nodejs, и там также прописано в 'Origin', 'https://sso.garmin.com', иначе Гарминовский сайт возвращает пустую строку, а должен вернуть Cross-Site Request Forgery (CSRF) token
Если переписать браузерный код с XMLHttpRequest на axios, то получится выставить headers нужные для авторизации или это безнадежно?
|
|
09.03.2021, 19:19
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,744
|
|
Сообщение от voraa
|
Я думаю не получится считать файл, если страница берется с локального компьютера используя XMLHttpRequest или fetch.
|
Это я опять жутко поторопился.
На самом деле МОЖНО!
Все дело в заголовках, которые посылает сервер
Вот такой простецкий сервер на nodejs
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Access-Control-Allow-Origin', '*'); // !important
res.setHeader('Access-Control-Allow-Headers', 'origin, content-type, accept'); // !important
res.end('Hello World with CORS!');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
И вот такой html файл, расположенный локально
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" lang="ru">
<meta name="viewport" content="width=device-width, initial-scale=1.0" >
<title>TESTE</title>
</head>
<body id="body">
<button type='button' id='bsend'>Send</button>
<br>
<div id='answ'>
</div>
</div>
<script>
document.getElementById('bsend').addEventListener('click',
async () => {
try {
const resp = await fetch('http://127.0.0.1:3000', {mode:'cors'})
let str = await resp.text();
document.getElementById('answ').innerHTML = str
console.log(str)
}catch (err){
document.getElementById('answ').innerHTML=`Error ${err.name} ${err.code} ${err.message}`;
}
}
);
</script>
</body>
</html>
Совершенно спокойно взаимодействуют.
|
|
10.03.2021, 02:25
|
Интересующийся
|
|
Регистрация: 17.02.2021
Сообщений: 27
|
|
Забанили
Garmin Express Error 1006 and 1015
After attempting multiple times to log in to Garmin Express, you may receive the following errors:
"Error 1015 error RAY ID 58c1fd3vaa9dd314. You are being rate limited. The owner of this website has banned you temporarily from accessing this website".
"Error 1006 Ray ID 5c7fda4d8a9a0d12. Access denied. The owner of this website (support.garmin.com) has banned your IP address (**.**.***.***).
This is the expected behavior and is displayed when too many attempts have been made to log in. The account will be unblocked after 24 hours automatically. Please wait 24 hours before trying to sign in again.
не так то просто отладить код при общении с чужим сайтом
|
|
11.03.2021, 17:44
|
Интересующийся
|
|
Регистрация: 17.02.2021
Сообщений: 27
|
|
Меня разбанили и я кажется разобрался как правильно надо поступать.
Идея была в том чтобы прикрутить fitplotter к внешнему независимому сайту и скачивать оттда тренировки для анализа. Этот сайт требует аторизациии, считается что каждый пользователь эту автризацию проходит сам.
Если просто скачивать по одному файлу с сайта, то все работает, и каждый раз юзер общается с диалогом save as - куча ненужных кликов.
Если пытаться скачивать автоматически из браузера, то нельзя подменить заголовок и ничего не получается
Решение такое. Ставить свой сервер, на нем предварительно делать авторизацию на чужом сервере. Клиентская программа должна сначала обращаться к своему серверу, на котором прошла авторизация, и уже с него идти за файлами к чужому серверу.
Если чужой сервер такую практику приветствует, то он публикует свой API для доступа. Так сделала strava (и получается что если бы работал с ней, то я бы ломился в открытую дверь.) А Garmin такую практику осуждает и на гитхабе программисты матом исходят пытаясь разобраться что там Garmin придумал чтобы затруднить программную авторизацию.
У меня есть отдельные куски для сервера и клиента, надо ли их сшивать - это теперь больше политический вопрос чем технический
А если работать со strava, то она не выдает сырые файлы, из-за которых собственно весь проект начался.
И ходят слухи что Garmin якобы откроет свой АПИ.
Конечно, такие вещи надо знать до а не после. Неделя головоломки - это я дешево отлелался
|
|
11.03.2021, 18:24
|
Интересующийся
|
|
Регистрация: 17.02.2021
Сообщений: 27
|
|
Сообщение от voraa
|
Все дело в заголовках, которые посылает сервер
Вот такой простецкий сервер на nodejs
|
да, именно так, нужен свой сервер для подмены заголовков.
Есть некий адрес, который становится доступным после авторизации. Допустим, я авторизовался как человек через окно браузера. До авторизации мне этот адрес недоступен, после я могу открыть его и прочитать содержимое страницы глазами и вручную скопировать, сохранить как файл и проч. Но всё вручную, автоматизировать через браузер не получается, для этого нужны серверные команды.
А если делать через сервер, то надо сначала делать авторизацию через сервер, и все команды для автоматического чтения файла посылать через этот сервер
|
|
|
|