Reputation: 223
I'm trying to read telegram messages from https://web.telegram.org with selenium.
When i open https://web.telegram.org in firefox i'm already logged in, but when opening the same page from selenium webdriver(firefox) i get the login page.
I saw that telegram web is not using cookies for the auth but rather saves values in local storage. I can access the local storage with selenium and have keys there such as: "dc2_auth_key", "dc2_server_salt", "dc4_auth_key", ... but I'm not sure what to do with them in order to login(and if i do need to do something with them then why? its the same browser why wont it work the same when opening without selenium?)
To reproduce:
open firefox and login to https://web.telegram.org then run this code:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("https://web.telegram.org")
# my code is here but is irrelevant since im at the login page.
driver.close()
Upvotes: 1
Views: 6387
Reputation: 11
I was able to figure out how to save and log in using cookies in web telegram. Only the code for playwright. Maybe this code will work for someone too.
Thanks to Sergey Litvinov and Amir Adibi for help!
import json
from playwright.sync_api import sync_playwright
def get_credential_tokens(page):
tokens = page.evaluate(
"""
(function() {
var tokens = {};
for (var i = 0; i < localStorage.length; i++) {
tokens[localStorage.key(i)] = localStorage.getItem(localStorage.key(i));
}
return tokens;
})();
"""
)
return tokens
def save_credentials(credentials) -> None:
with open("tokens.json", "w") as f:
json.dump(credentials, f)
def load_and_format_credentials(file_path: str):
# Loading data from a JSON file
with open(file_path, "r") as f:
credentials = json.load(f)
# Извлекаем и форматируем нужные ключи
keys_to_extract = ["dc4_auth_key", "dc3_auth_key", "dc2_auth_key", "user_auth"]
formatted_credentials = {}
for key in keys_to_extract:
if key in credentials:
value = credentials[key].strip('"')
# Проверка на наличие JSON-объекта
if value.startswith("{") and value.endswith("}"):
# Convert a JSON object to a string with escaped quotes
formatted_credentials[key] = f'{{{value[1:-1]}}}'
else:
# A regular string with outer quotes
formatted_credentials[key] = f'\\"{value}\\"'
return formatted_credentials
def set_item(page, key, value):
page.evaluate(f"localStorage.setItem('{key}', '{value}')")
def main():
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
# Switching to Telegram Web
page.goto("https://web.telegram.org/")
# For the first launch - wait for login and save tokens
input("After logging into Telegram, press Enter to save tokens...")
credentials = get_credential_tokens(page)
save_credentials(credentials)
print("Tokens are saved in the tokens.json file")
# Login by cookie thing (Launch after saving file)
# page.evaluate("localStorage.clear()")
# result = load_and_format_credentials("tokens.json")
# for key, value in result.items():
# print(f"{key}: {value}")
# set_item(page, key, value)
# Refresh the page to apply the tokens
# page.reload()
# input("Tokens have been downloaded and applied.")
browser.close()
if __name__ == "__main__":
main()
Upvotes: 1
Reputation: 3
you can use this code to extract credential tokens from the browser's local storage, after logging in:
def get_credential_tokens(driver):
tokens = driver.execute_script(
"var tokens = {};\
for (var i = 0; i < localStorage.length; i++){\
tokens[localStorage.key(i)] = localStorage.getItem(localStorage.key(i));\
};\
return tokens;"
)
return tokens
you can store it in a JSON file or your .env file and read it from there and set it in the browser's local storage as follow:
credentials = load_credentials()
for key, value in credentials.items():
set_item(key, value)
where the set_item()
function is:
def set_item(driver, key, value):
driver.execute_script("window.localStorage.setItem(arguments[0], arguments[1]);", key, value)
and the load_credentials()
function is:
def __load_credentials() -> Dict:
with open("tokens.json", "r") as f:
credentials = json.load(f)
return credentials
you can also save the credentials in a JSON file this way:
def save_credentials(credentials) -> None:
with open("tokens.json", "w") as f:
json.dump(credentials, f)
Upvotes: 0
Reputation: 1
You can auth using your current data from local storage. Example:
driver.get(TELEGRAM_WEB_URL);
LocalStorage localStorage = ((ChromeDriver) DRIVER).getLocalStorage();
localStorage.clear();
localStorage.setItem("dc2_auth_key","<YOUR AUTH KEY>");
localStorage.setItem("user_auth","<YOUR USER INFO>");
driver.get(TELEGRAM_WEB_URL);
Upvotes: 0
Reputation: 193058
When you open https://web.telegram.org
manually using Firefox, the Default Firefox Profile is used. As you login and browse through the website, the websites stores Authentication Cookies within your system. As the cookies gets stored within the local storage of the Default Firefox Profile even on reopening the browsers you are automatically authenticated.
But when GeckoDriver initiates a new web browsing session for your tests everytime a temporary new mozprofile is created while launching Firefox which is evident from the following log:
mozrunner::runner INFO Running command: "C:\\Program Files\\Mozilla Firefox\\firefox.exe" "-marionette" "-profile" "C:\\Users\\ATECHM~1\\AppData\\Local\\Temp\\rust_mozprofile.fDJt0BIqNu0n"
You can find a detailed discussion in Is it Firefox or Geckodriver, which creates “rust_mozprofile” directory
Once the Test Execution completes and quit()
is invoked the temporary mozprofile is deleted in the following process:
webdriver::server DEBUG -> DELETE /session/f84dbafc-4166-4a08-afd3-79b98bad1470
geckodriver::marionette TRACE -> 37:[0,3,"quit",{"flags":["eForceQuit"]}]
Marionette TRACE 0 -> [0,3,"quit",{"flags":["eForceQuit"]}]
Marionette DEBUG New connections will no longer be accepted
Marionette TRACE 0 <- [1,3,null,{"cause":"shutdown"}]
geckodriver::marionette TRACE <- [1,3,null,{"cause":"shutdown"}]
webdriver::server DEBUG Deleting session
geckodriver::marionette DEBUG Stopping browser process
So, when you open the same page using Selenium, GeckoDriver and Firefox the cookies which were stored within the local storage of the Default Firefox Profile aren't accessible and hence you are redirected to the Login Page.
To store and use the cookies within the local storage to get authenticated automatically you need to create and use a Custom Firefox Profile.
Here you can find a relevant discussion on webdriver.FirefoxProfile(): Is it possible to use a profile without making a copy of it?
Upvotes: 7