Added a lot to the JDB

This commit is contained in:
2023-04-18 17:10:57 +02:00
parent d494c98656
commit a5708b4ab8
+166 -1
View File
@@ -1483,4 +1483,169 @@ FirefoxOptions options = new FirefoxOptions();
var driver = new FirefoxDriver(service,options);
```
Le seul problème c'est que du coup il faut tout le temps déplacer le fichier dans le dossier bin si je clone le projet. Il faudra faire un installeur dans la version finale qui s'occupe de tout je pense.
Le seul problème c'est que du coup il faut tout le temps déplacer le fichier dans le dossier bin si je clone le projet. Il faudra faire un installeur dans la version finale qui s'occupe de tout je pense.
Je me suis dit que j'allais garder la doc pour le retour des vacances quand j'aurai un bureau un clavier et un setup complet un peu propres.
Bon il va falloir que je parle de la récupération de cookie.
J'ai déja pu travailler lors d'un poc sur la meilleure facon de prendres des screenshots de la F1TV :
- Avoir une page chrome ouverte avec le feed en plein écran et un programme qui prend des captures d'écrans.
- Avoir une caméra qui prend en photo l'écran au cas ou chrome et Firefox empêchent la prise de captures d'écrans.
- Récupèrer directement le feed en faisant du reverse engeneering de la plateforme.
- Simuler un chrome en background qui prenne des screenshot sans qu'on aie à le voir.
Dans toutes ces options, je dirais que la pire était celle de la caméra qui filme l'écran, mais à l'époque c'était encore envisageable comme solution de dernier recours. Le soucis de cette solution c'est l'horreur que serait la partie OCR avec une image de très mauvaise qualité.
Une autre option qui m'aurait vraiment embêté aurait été de devoir garder une page de Chrome ou Firefox ouverte quelque part sur un écran pour que le programme puisse prendres des captures d'écrans. C'est de loin l'option la plus simple et la plus logique mais elle possède pour moi de très gros points noirs :
- On ne peut pas certifier l'intégrité des données car l'utilisateur a le contrôle total sur le feed. Il peut mettre pause, avancer, reculer, tout casser sans faire exprès en ouvrant autre chose sur son ordi qui se mette pile devant. Bref c'est un peu bancale.
- Et surtout on bloque une partie non significative de l'écran de l'utilisateur avec des infos redondantes. Et je peux vous dire que quand je commente la F1 j'ai besoin de beaucoup d'informations et que chaque centimètre d'écran est cruciaé ! Alors avoir un écran complet bloqué est juste un point bloquant qui m'empêcherait d'utiliser l'app aussi bonne soit-elle dans ses prédictions.
Mais bon si aucune autre methode ne fonctionne ce qui est bien c'est que celle la est plutôt simple à mettre en place.
Ensuite reverse engeneer le feed serait l'option la plus classe, cependant c'est la plus complexe et la plus bancale au niveau légal haha. L'idée serait de récupèrer le lien vers le broadcast général et de comprendre comment il fonctionne pour le décoder nous même pendant un Grand Prix.
Seuls soucis :
- Il n'est pas possible de faire des tests en dehors des periodes de Grand Prix (Et je rappelle que c'est des périodes ou je travaille en plus)
- Difficile de faire un système qui marche pareil pour les rediffusions et les lives. (En effet les liens des rediff sont beaucoup plus simple à récupèrer mais ne fonctionnent pas du tout pareil et pour tester l'app il est essentiel de pouvoir s'entrainer sur des anciens Grand Prix)
- Dernier GROS soucis, je ne sais tout simplement pas faire ca lol. Je ne sais pas comment faire. Peut-être que avec des profs qui m'aident et chat gpt ainsi qu'internet je pourrais potentiellement négocier un truc mais c'est hautement improbable et cela serait une perte de temps folle si je n'y arrive pas.
Dernière option que je trouve la plus séduisante. Simuler une instance de Chrome ou de Firefox (Le soucis avec chrome c'est qu'il implémente l'utilisation de DRM dans les vidéos qui fait qu'il est très difficile de passer outre la sécurité avec un bot) pour ensuite prendre des captures d'écrans automatiquement. Cette solutions offre pleins d'avantages :
- Pas de place prise sur l'écran
- L'intégrité des données est assurée car c'est le programme qui décide d'ou partir et de si il met pause ou non
- C'est une option complexe mais beaucoup moins que le reverse engeneering
- Elle permet de ne demander presque aucun input de la part de l'utilisateur.
Mais elle pose quelques problématiques :
- Comment se connecter automatiquement sans être detecté par un Bot et sans demander à l'utilisateur ses identifiants (Pour des raisons évidentes qui sont : QUI VA METTRE SES IDENTIFIANTS SUR UNE VIEILLE APP COMME LA MIENNE??)
- Comment faire en sorte que le programme prenne les meilleures captures dans la meilleure qualité et en plein écran.
Mais j'ai décidé de partir sur cette option.
Pour ce faire j'utilise Selenium. J'ai pu tester Puppetteer Sharp et même si dans un premier temps j'ai pu avancer asez vite, malheureusement il y a des bugs qui rendent son utilisation impossible dans notre contexte.
J'ai donc décidé de tout faire en utilisant un portage de Selenium dans mon programme.
Voici un exemple de code qui va ouvrir FireFox et qui va lancer un RickRoll
```Csharp
var service = FirefoxDriverService.CreateDefaultService(AppDomain.CurrentDomain.BaseDirectory+@"geckodriver-v0.27.0-win32\geckodriver.exe");
service.Host = "127.0.0.1";
service.Port = 5555;
FirefoxOptions options = new FirefoxOptions();
options.AddArgument("--disable-headless");
var driver = new FirefoxDriver(service,options);
driver.Navigate().GoToUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ&autoplay=1&mute=1");
```
Dans cet exemple on désactive le "Headless" pour qu'on puisse voir ce que fait l'app car sinon tout est invisible.
Alors dans les faits la vidéo youtube ne se lance pas du tout car il y a des pubs et des prompts de cookies que l'on doit accepter etc... ce qui montre les différents challenges que l'on va devoir surmonter pour vraiment faire ce que l'on veut.
Mais un petit détail extrêmement important, la F1TV est un programme payant un peu comme netflix. Ce qui veut dire que pour accèder au contenu il faut être connecté. Sauf que une instance de firefox créé par Selenium est comme une page de naviguation privée, ce qui veut dire que si on va sur la page de la F1TV on est pas connectés.
Je pourrais tout à fait demander à l'utilisateur de me donner ses identifiants pour que j'aille ensuite automatiquement me connecter sauf que cela pose deux soucis:
- Personne ne voudra mettre ses identifiants sur mon programme
- La page de login de la F1TV a été protègée avec la meilleure technologie de detection de bots que je connaisse. Presque aucun site n'arrive à me detecter sauf eux ! Donc c'est tout simplement impossible d'utiliser cette technique.
Ensuite je me suis rappelé que ce que la page stocke pour me permettre de rester connecté ce sont des cookies. Et si je mets le bon cookies dans Selenium alors je serai connecté.
Dans un premier temps je voulais faire un système ou l'utilisateur irait prendre dans son chrome son cookie et le copie colle dans mon programme mais c'est immonde.
C'est alors que vient la partie récupèration de cookies !
Tous les cookies de chrome sont stockés dans une base de données SQLITE. On pourrait se dire Banco il suffit d'aller dedans et de retrouver tous les cookies et se connecter. Sauf que, pas bêtes, les équipes de chrome ont décidé que c'était une bonne idée d'encoder les cookies pour que tout le monde ne puisse pas venir y mettre son nez... En effet les cookies peuvent contenir des informations importantes.
Cela fait que pour utiliser ces cookies il faut pouvoir les décoder. Mon hypothèse a été que si ces cookies peuvent être lus par Chrome même hors connexion, c'est que la clé de décodage existe sur l'appareil et qu'il suffit de la trouver. ET C'EST LE CAS! Après pas mal de recherches j'ai pu voir que la clé de décodage existe bel et bien et qu'il suffit de la décoder en utilisant la librairie DPAPI pour la lire.
Avec cette clé on peut ensuite décoder les cookies et leurs valeurs ce qui veut dire qu'il est théoriquement possible d'automatiser le processus sans que l'utilisateur n'aie rien à faire.
J'ai décidé de faire la partie récupèration en python pour deux raison :
- Je n'arrivais pas à trouver une bonne implémentation de DPAPI en C# qui me permettait de décoder la clé.
- Il existe beaucoup plus de documentation en Python pour ce qui est de la cryptographie et donc si Chrome change de fonctionnement il sera beaucoup plus simple de changer cette partie en particulier sans avoir à recompiler le code C#.
J'ai donc avec l'aide d'internet et de ChatGPT créé ce script :
```Python
def get_master_key():
with open(
os.getenv("localappdata") + "\\Google\\Chrome\\User Data\\Local State", "r"
) as f:
local_state = f.read()
local_state = json.loads(local_state)
master_key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
master_key = master_key[5:] # removing DPAPI
master_key = win32crypt.CryptUnprotectData(master_key, None, None, None, 0)[1]
print("MASTER KEY :")
print(master_key)
print(len(master_key))
return master_key
def decrypt_payload(cipher, payload):
return cipher.decrypt(payload)
def generate_cipher(aes_key, iv):
return AES.new(aes_key, AES.MODE_GCM, iv)
def decrypt_password(buff, master_key):
try:
iv = buff[3:15]
payload = buff[15:]
cipher = generate_cipher(master_key, iv)
decrypted_pass = decrypt_payload(cipher, payload)
decrypted_pass = decrypted_pass[:-16].decode() # remove suffix bytes
return decrypted_pass
except Exception:
# print("Probably saved password from Chrome version older than v80\n")
# print(str(e))
return "Chrome < 80"
master_key = get_master_key()
cookies_path = Path(
os.getenv("localappdata") + "\\Google\\Chrome\\User Data\\Default\\Network\\Cookies"
)
if not cookies_path.exists():
raise ValueError("Cookies file not found")
with sqlite3.connect(cookies_path) as connection:
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
cursor.execute("SELECT * FROM cookies")
with open('cookies.csv', 'a', newline='') as csvfile:
fieldnames = ['host_key', 'name', 'value', 'path', 'expires_utc', 'is_secure', 'is_httponly']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
if csvfile.tell() == 0:
writer.writeheader()
for row in cursor.fetchall():
decrypted_value = decrypt_password(row["encrypted_value"], master_key)
writer.writerow({
'host_key': row["host_key"],
'name': row["name"],
'value': decrypted_value,
'path': row["path"],
'expires_utc': row["expires_utc"],
'is_secure': row["is_secure"],
'is_httponly': row["is_httponly"]
})
print("Finished CSV")
```
Ce programme va faire tout ce que j'ai expliqué et va ensuite stocker les résultats dans un CSV pour qu'il soit facile d'y accèder depuis le C#.
Alors oui cela pose certaines questions de sécurité. Car en effet je prend tous les cookies, les décode et les stocke. Ce qui veut dire que je pourrais tout à fait envoyer ces données quelque part, par exemple un compte Netflix, et me rincer.
Si je devais rendre le projet ouvert au public je pense qu'il faudra que cela soit mentionné clairement et que le projet soit open source pour que les utilisateurs puissent verifier que je ne fais pas ca.