« Documentation de l'API Jeuxvideo.com » : différence entre les versions
m (→API endpoints) |
(PUT, DELETE, explication sur comment trouver l'API) |
||
Ligne 1 : | Ligne 1 : | ||
L''''API de [[Jeuxvideo.com]]''', utilisée à l'origine par les applications mobiles de Jeuxvideo.com, permet de développer plus facilement des applications, sites web, et autres scripts en rapport avec Jeuxvideo.com. | L''''API de [[Jeuxvideo.com]]''', utilisée à l'origine par les applications mobiles de Jeuxvideo.com, permet de développer plus facilement des applications, sites web, et autres scripts en rapport avec Jeuxvideo.com. | ||
Ligne 32 : | Ligne 31 : | ||
URL de base de l'API : ''<nowiki>https://api.jeuxvideo.com/v4/</nowiki>'' | URL de base de l'API : ''<nowiki>https://api.jeuxvideo.com/v4/</nowiki>'' | ||
* URL : endpoint | * '''T''' : Est-ce que l'endpoint à été testé ? N = non, O = Oui | ||
* PARAMS : variable entre accolades à remplacer dans l'URL, suivi de son type ''str'' ou ''int''. | * '''URL''' : url de l'endpoint | ||
* '''PARAMS''' : variable entre accolades à remplacer dans l'URL, suivi de son type ''str'' ou ''int''. | |||
** <code>contents/{contentID}/comments</code> doit être appelé comme suivant <code>contents/someID1234/comments</code> | ** <code>contents/{contentID}/comments</code> doit être appelé comme suivant <code>contents/someID1234/comments</code> | ||
* BODY : corps de la requête au format JSON donc <code>"content": "commentaire"</code> sera en réalité : | * '''QUERY''' : ?page=1& | ||
* '''BODY''' : corps de la requête au format JSON donc <code>"content": "commentaire"</code> sera en réalité : | |||
<pre> | <pre> | ||
{ | { | ||
Ligne 47 : | Ligne 48 : | ||
!PARAMS | !PARAMS | ||
!BODY | !BODY | ||
!T | |||
|- | |- | ||
|addComment | |addComment | ||
Ligne 52 : | Ligne 54 : | ||
|'''contentID''' str | |'''contentID''' str | ||
|<pre>"content": "commentaire"</pre> | |<pre>"content": "commentaire"</pre> | ||
|N | |||
|- | |- | ||
|addCommentVote | |addCommentVote | ||
Ligne 58 : | Ligne 61 : | ||
'''commentID''' str | '''commentID''' str | ||
|<pre>"type": 1 ou -1</pre> | |<pre>"type": 1 ou -1</pre> | ||
|N | |||
|- | |- | ||
|addFavorisGames | |addFavorisGames | ||
Ligne 67 : | Ligne 71 : | ||
]} | ]} | ||
</pre> | </pre> | ||
|N | |||
|- | |- | ||
|addReply | |addReply | ||
Ligne 74 : | Ligne 78 : | ||
'''commentID''' str | '''commentID''' str | ||
|<code>"content": "Super jeu !"</code> | |<code>"content": "Super jeu !"</code> | ||
|N | |||
|- | |- | ||
|addReview | |addReview | ||
Ligne 84 : | Ligne 89 : | ||
"onProfile": true | "onProfile": true | ||
</pre> | </pre> | ||
|N | |||
|- | |- | ||
|login | |login | ||
Ligne 91 : | Ligne 97 : | ||
"password": "mot_de_passe" | "password": "mot_de_passe" | ||
|O | |||
|- | |- | ||
|logout | |logout | ||
Ligne 96 : | Ligne 103 : | ||
| | | | ||
| | | | ||
|O | |||
|- | |- | ||
|register | |register | ||
Ligne 106 : | Ligne 114 : | ||
"optin": false | "optin": false | ||
</pre> | </pre> | ||
|N | |||
|- | |- | ||
|reinitPassword | |reinitPassword | ||
Ligne 122 : | Ligne 131 : | ||
"val2" ]} | "val2" ]} | ||
</pre> | </pre> | ||
|N | |||
|- | |- | ||
|reportAccount | |reportAccount | ||
Ligne 129 : | Ligne 139 : | ||
<code>"message": "Raison"</code> | <code>"message": "Raison"</code> | ||
|N | |||
|- | |- | ||
|reportComment | |reportComment | ||
Ligne 142 : | Ligne 153 : | ||
} | } | ||
</pre> | </pre> | ||
|N | |||
|- | |- | ||
|reportReview | |reportReview | ||
Ligne 155 : | Ligne 167 : | ||
"valeur_captcha": "" | "valeur_captcha": "" | ||
}</pre> | }</pre> | ||
|N | |||
|- | |- | ||
|restoreComment | |restoreComment | ||
Ligne 161 : | Ligne 174 : | ||
'''commentID''' str | '''commentID''' str | ||
|"content" : "comment" | |"content" : "comment" | ||
|N | |||
|- | |- | ||
|validateAccount | |validateAccount | ||
Ligne 170 : | Ligne 184 : | ||
"password": "mdp" | "password": "mdp" | ||
</pre> | </pre> | ||
|N | |||
|- | |- | ||
|validateSignature | |validateSignature | ||
Ligne 177 : | Ligne 192 : | ||
"signed_data": "signed_data" | "signed_data": "signed_data" | ||
</pre> | </pre> | ||
|N | |||
|} | |} | ||
{| class="wikitable mw-collapsible" | {| class="wikitable mw-collapsible" | ||
Ligne 185 : | Ligne 201 : | ||
!QUERY | !QUERY | ||
!HEADER | !HEADER | ||
!T | |||
|- | |- | ||
|config | |config | ||
Ligne 191 : | Ligne 208 : | ||
| | | | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getAccount | |getAccount | ||
Ligne 197 : | Ligne 215 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getAllFavorisGames | |getAllFavorisGames | ||
Ligne 203 : | Ligne 222 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getArticle | |getArticle | ||
Ligne 209 : | Ligne 229 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getArticleList | |getArticleList | ||
Ligne 217 : | Ligne 238 : | ||
'''types''' str | '''types''' str | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getCaptcha | |getCaptcha | ||
Ligne 223 : | Ligne 245 : | ||
|'''nb''' int | |'''nb''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getChroniclesSummary | |getChroniclesSummary | ||
Ligne 229 : | Ligne 252 : | ||
|'''machines''' str | |'''machines''' str | ||
| | | | ||
|N | |||
|- | |- | ||
|getComment | |getComment | ||
Ligne 236 : | Ligne 260 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getCommentAnswers | |getCommentAnswers | ||
Ligne 243 : | Ligne 268 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getComments | |getComments | ||
Ligne 250 : | Ligne 276 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getContentBean | |getContentBean | ||
|contents/{id} | |contents/{id} | ||
|'''id''' int | |'''id''' int | ||
| | |||
| | | | ||
| | | | ||
Ligne 267 : | Ligne 295 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getCurrentAccountReport | |getCurrentAccountReport | ||
|accounts/{accountId}/report | |accounts/{accountId}/report | ||
|'''accountId''' str | |'''accountId''' str | ||
| | |||
| | | | ||
| | | | ||
Ligne 280 : | Ligne 310 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getCurrentReviewReport | |getCurrentReviewReport | ||
Ligne 288 : | Ligne 319 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getFavoris | |getFavoris | ||
Ligne 294 : | Ligne 326 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getFavorisForum | |getFavorisForum | ||
Ligne 301 : | Ligne 334 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getFavorisGames | |getFavorisGames | ||
Ligne 307 : | Ligne 341 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getFavorisTopics | |getFavorisTopics | ||
Ligne 314 : | Ligne 349 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getFolder | |getFolder | ||
Ligne 320 : | Ligne 356 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getGame | |getGame | ||
Ligne 327 : | Ligne 364 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameDetails | |getGameDetails | ||
Ligne 334 : | Ligne 372 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameImages | |getGameImages | ||
Ligne 342 : | Ligne 381 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameList | |getGameList | ||
Ligne 353 : | Ligne 393 : | ||
'''perPage''' int | '''perPage''' int | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getGameNews | |getGameNews | ||
Ligne 360 : | Ligne 401 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameReleaseList | |getGameReleaseList | ||
Ligne 370 : | Ligne 412 : | ||
'''perPage''' int | '''perPage''' int | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getGameReview | |getGameReview | ||
Ligne 378 : | Ligne 421 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameReviews | |getGameReviews | ||
Ligne 384 : | Ligne 428 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameReviews | |getGameReviews | ||
Ligne 391 : | Ligne 436 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameSummary | |getGameSummary | ||
Ligne 397 : | Ligne 443 : | ||
|'''machines''' str | |'''machines''' str | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameUserReviews | |getGameUserReviews | ||
Ligne 405 : | Ligne 452 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameVideos | |getGameVideos | ||
Ligne 413 : | Ligne 461 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getGameWikis | |getGameWikis | ||
Ligne 421 : | Ligne 470 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getHeadlineList | |getHeadlineList | ||
Ligne 429 : | Ligne 479 : | ||
'''perPage''' int | '''perPage''' int | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getHighTechSummary | |getHighTechSummary | ||
Ligne 435 : | Ligne 486 : | ||
|'''machines''' str | |'''machines''' str | ||
| | | | ||
|N | |||
|- | |- | ||
|getLightGame | |getLightGame | ||
Ligne 442 : | Ligne 494 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getNews | |getNews | ||
Ligne 448 : | Ligne 501 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getNewsHighTech | |getNewsHighTech | ||
Ligne 455 : | Ligne 509 : | ||
'''perPage''' int | '''perPage''' int | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getPageContents | |getPageContents | ||
Ligne 462 : | Ligne 517 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getPageReviews | |getPageReviews | ||
Ligne 469 : | Ligne 525 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getProfile | |getProfile | ||
Ligne 475 : | Ligne 532 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getProfilePage | |getProfilePage | ||
Ligne 481 : | Ligne 539 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getRelatedNews | |getRelatedNews | ||
Ligne 488 : | Ligne 547 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getRelatedVideos | |getRelatedVideos | ||
Ligne 495 : | Ligne 555 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getRelatedWikis | |getRelatedWikis | ||
Ligne 502 : | Ligne 563 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|getSpecificNews | |getSpecificNews | ||
Ligne 508 : | Ligne 570 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getStores | |getStores | ||
Ligne 515 : | Ligne 578 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getTechList | |getTechList | ||
Ligne 522 : | Ligne 586 : | ||
'''perPage''' int | '''perPage''' int | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getTopWikis | |getTopWikis | ||
Ligne 528 : | Ligne 593 : | ||
| | | | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getTopsComments | |getTopsComments | ||
Ligne 534 : | Ligne 600 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getVideo | |getVideo | ||
Ligne 540 : | Ligne 607 : | ||
| | | | ||
| | | | ||
|N | |||
|- | |- | ||
|getVideoList | |getVideoList | ||
Ligne 551 : | Ligne 619 : | ||
'''perPage''' int | '''perPage''' int | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|- | |- | ||
|getVideosSummary | |getVideosSummary | ||
Ligne 557 : | Ligne 626 : | ||
|'''machines''' str | |'''machines''' str | ||
| | | | ||
|N | |||
|- | |- | ||
|search | |search | ||
Ligne 563 : | Ligne 633 : | ||
|'''q''' str | |'''q''' str | ||
| | | | ||
|N | |||
|- | |- | ||
|searchArticles | |searchArticles | ||
Ligne 571 : | Ligne 642 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|searchAutocomplete | |searchAutocomplete | ||
Ligne 577 : | Ligne 649 : | ||
|'''q''' str | |'''q''' str | ||
| | | | ||
|N | |||
|- | |- | ||
|searchGames | |searchGames | ||
Ligne 585 : | Ligne 658 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|searchNews | |searchNews | ||
Ligne 593 : | Ligne 667 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|searchVideos | |searchVideos | ||
Ligne 601 : | Ligne 676 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|searchWikis | |searchWikis | ||
Ligne 609 : | Ligne 685 : | ||
'''perPage''' int | '''perPage''' int | ||
| | | | ||
|N | |||
|- | |- | ||
|sponso | |sponso | ||
Ligne 615 : | Ligne 692 : | ||
| | | | ||
|'''If-None-Match''' str | |'''If-None-Match''' str | ||
|N | |||
|} | |||
{| class="wikitable mw-collapsible" | |||
|+PUT | |||
!NOM | |||
!URL | |||
!PARAMS | |||
!BODY | |||
!T | |||
|- | |||
|saveDescription | |||
|accounts/me/profile/description | |||
| | |||
|''rétro-ingénierie à faire'' | |||
|N | |||
|- | |||
|saveExcludedMachines | |||
|accounts/me/profile/excluded-machines | |||
| | |||
|"machines" : [1, 2, 3, 4] // id des machines | |||
|N | |||
|- | |||
|saveMachines | |||
|accounts/me/profile/machines | |||
| | |||
|"machines" : [1, 2, 3, 4] // id des machines | |||
|N | |||
|- | |||
|updateComment | |||
|contents/{contentID}/comments/{commentID} | |||
|'''contentID''' str | |||
'''commentID''' str | |||
|"content": "Super jeu !" | |||
|N | |||
|- | |||
|uploadAvatar | |||
|accounts/me/avatar | |||
| | |||
|''rétro-ingénierie à faire'' | |||
|N | |||
|- | |||
|uploadCover | |||
|accounts/me/cover | |||
| | |||
|''rétro-ingénierie à faire'' | |||
|N | |||
|} | |} | ||
{| class="wikitable" | |||
|+DELETE | |||
!NOM | |||
!URL | |||
!PARAMS | |||
!T | |||
|- | |||
|deleteComment | |||
|contents/{contentID}/comments/{commentID} | |||
|'''contentID''' str | |||
'''commentID''' str | |||
|N | |||
|- | |||
|deleteCommentVote | |||
|contents/{contentID}/comments/{commentID}/vote | |||
|'''contentID''' str | |||
'''commentID''' str | |||
|N | |||
|} | |||
{| class="wikitable" | |||
|+CUSTOM HTTP (''rétro-ingénierie à faire'') | |||
!NOM | |||
!URL | |||
!PARAMS | |||
!T | |||
|- | |||
|deleteFavorisForum | |||
|accounts/{accountId}/favorites/forums | |||
|'''accountId''' str | |||
|N | |||
|- | |||
|deleteFavorisGames | |||
|accounts/{accountId}/favorites/games | |||
|'''accountId''' str | |||
|N | |||
|- | |||
|deleteFavorisTopics | |||
|accounts/{accountId}/favorites/topics | |||
|'''accountId''' str | |||
|N | |||
|} | |||
== Rétro-ingénierie de l'API == | |||
Pour connaître les endpoints de l'API, il faut décompiler l'appli JVC. | |||
# Décompresser l'APK de l'application avec 7zip/Winrar/etc. | |||
# Utiliser un décompilateur Dex vers Java, comme '''[https://github.com/skylot/jadx Jadx]''' . | |||
Une fois le code Java disponible, on peut ouvrir l'interface ''com.jeuxvideo.api.web.'''JvApiService''''', qui contient tous les endpoints. L'appli utilise le bibliothèque [https://square.github.io/retrofit/ Retrofit 2.x] pour gérer l'API, on peut facilement parcourir la documentation de cette bibliothèque pour découvrir ce qu'il faut faire comme requête aux différentes URL de l'API. | |||
La classe ''com.jeuxvideo.utils.'''ApiLogin''''' (nom de la classe donné arbitrairement car perdu lors de la compilation), permet de déduire qu'il faut mettre dans le header de la requête à l'API ''Jvc-Authorization : '''header''''' ainsi que l'algorithme permettant de trouver ce qu'il faut mettre à la place de '''''header'''''. | |||
==Classe PHP exploitant l'API== | ==Classe PHP exploitant l'API== |
Version du 5 septembre 2023 à 16:09
L'API de Jeuxvideo.com, utilisée à l'origine par les applications mobiles de Jeuxvideo.com, permet de développer plus facilement des applications, sites web, et autres scripts en rapport avec Jeuxvideo.com.
Elle est au format JSON[1], ce qui fait qu'elle est plus facile à parser[2], mais aussi plus rapide à charger qu'une page web normale.
L'ancienne API était hébergée sur le sous-domaine "ws". Désormais, l'API est hébergée sur le sous-domaine "api", et est actuellement à sa quatrième version (v4).
API v4
L'API v4 utilise un système de sécurité afin que même personne ne puisse accéder à l'API. Pour pouvoir accéder y accéder, l'Header de vos requêtes devra toujours être de la forme :
Jvc-Authorization: "header"
"User-Agent": "JeuxVideo-Android/267"
"Content-Type" : "application/json"
Où header est égal à une chaîne de charactère de cette forme : "PartnerKey=partner_key, Signature=signature, Timestamp=date". (Voir section rétro-ingénierie pour plus d'information)
Voici un script python qui construit la signature
import hashlib from datetime import datetime api_version = 4 partner_key = "550c04bf5cb2b" date = datetime.utcnow().isoformat() method = "POST" signature = hashlib.sha256(f"{self.partner_key}\n{date}\n{method}\napi.jeuxvideo.com\n/v{self.api_version}/{path}".encode()).hexdigest() header = f"PartnerKey={partner_key}, Signature={signature}, Timestamp={date}"
API endpoints
Modèle:BoxNotice URL de base de l'API : https://api.jeuxvideo.com/v4/
- T : Est-ce que l'endpoint à été testé ? N = non, O = Oui
- URL : url de l'endpoint
- PARAMS : variable entre accolades à remplacer dans l'URL, suivi de son type str ou int.
contents/{contentID}/comments
doit être appelé comme suivantcontents/someID1234/comments
- QUERY : ?page=1&
- BODY : corps de la requête au format JSON donc
"content": "commentaire"
sera en réalité :
{ "content": "commentaire" }
NOM | URL | PARAMS | BODY | T |
---|---|---|---|---|
addComment | contents/{contentID}/comments | contentID str | "content": "commentaire" |
N |
addCommentVote | contents/{contentID}/comments/{commentID}/vote | contentID str
commentID str |
"type": 1 ou -1 |
N |
addFavorisGames | accounts/{accountId}/favorites/games | accountId str | "games": [{ "id": 1,</code> "machine": 100 ]} |
N |
addReply | contents/{contentID}/comments/{commentID}/answers | contentID str
commentID str |
"content": "Super jeu !"
|
N |
addReview | games/{id}/{machine}/reviews/users | id int
machine str |
"content": "Super jeu !", "mark": 4,</code> "onProfile": true |
N |
login | accounts/login | "alias": "pseudo",
"password": "mot_de_passe" |
O | |
logout | accounts/logout | O | ||
register | accounts/register
l'Header doit inclure : |
"email": "email", "alias": "pseudo", "password": "motdepasse", "optin": false |
N | |
reinitPassword | accounts/reset | "alias": "pseudo", "password": "nouveau",</code> "session": "",</code> "captcha": {</code> "imageKey": "",</code> "imageName": "",</code> "imageValues": [</code> "val1",</code> "val2" ]} |
N | |
reportAccount | accounts/{accountId}/report | accountId str | "reason": 1,
|
N |
reportComment | contents/{contentID}/comments/{commentID}/report | contentID str
commentID str |
"reason": 1, "message": "Raison", "captcha": { "session": "clé" "clé_captcha": "Valeur" "valeur_captcha": "Valeur" } |
N |
reportReview | games/{id}/{machine}/reviews/users/{reviewId}/report | id int
machine str reviewId int |
"reason": 1, "message": "Raison", "captcha": { "session": "clé" "clé_captcha": "" "valeur_captcha": "" } |
N |
restoreComment | contents/{contentID}/comments/{commentID} | contentID str
commentID str |
"content" : "comment" | N |
validateAccount | accounts/confirm | "id": 123, "hash": "hash", "alias": "pseudo", "password": "mdp" |
N | |
validateSignature | general/stores/android/validation | "signature": "signature", "signed_data": "signed_data" |
N |
NOM | URL | PARAMS | QUERY | HEADER | T |
---|---|---|---|---|---|
config | general/config | If-None-Match str | N | ||
getAccount | accounts/{accountId} | accountId str | N | ||
getAllFavorisGames | accounts/{accountId}/favorites/games/all | accountId str | N | ||
getArticle | contents/{id} | id int | N | ||
getArticleList | rétro-ingénierie à faire | page int
perPage int types str |
If-None-Match str | N | |
getCaptcha | captcha/start | nb int | N | ||
getChroniclesSummary | contents/chronicles | machines str | N | ||
getComment | contents/{contentID}/comments/{commentID} | contentID str
commentID str |
N | ||
getCommentAnswers | contents/{contentID}/comments/{commentID}/answers | contentID str
commentID str |
N | ||
getComments | contents/{contentID}/comments | contentID str | page int
perPage int |
N | |
getContentBean | contents/{id} | id int | |||
getContentList | rétro-ingénierie à faire | categories str
types str events str machines str page int perPage int |
N | ||
getCurrentAccountReport | accounts/{accountId}/report | accountId str | |||
getCurrentCommentReport | contents/{contentID}/comments/{commentID}/report | contentID str
commentID str |
N | ||
getCurrentReviewReport | games/{id}/{machine}/reviews/users/{reviewId}/report | id int
machine str reviewId int |
N | ||
getFavoris | accounts/{accountId}/favorites | accountId str | N | ||
getFavorisForum | accounts/{accountId}/favorites/forums | accountId str | page int
perPage int |
N | |
getFavorisGames | accounts/{accountId}/favorites/games | accountId str | N | ||
getFavorisTopics | accounts/{accountId}/favorites/topics | accountId str | page int
perPage int |
N | |
getFolder | contents/{id} | id int | N | ||
getGame | games/{id}/{machine} | id int
machine str |
N | ||
getGameDetails | games/{id}/{machine}/details | id int
machine str |
N | ||
getGameImages | games/{id}/{machine}/images | id int
machine str |
page int
perPage int |
N | |
getGameList | games/{type} | type str | machines str
machine str genre str mode str page int perPage int |
If-None-Match str | N |
getGameNews | games/{id}/{machine}/news | id int | page int
perPage int |
N | |
getGameReleaseList | games/releases | month str
year str machines str page int perPage int |
If-None-Match str | N | |
getGameReview | games/{id}/{machine}/reviews/users/{review} | id int
machine str review str |
N | ||
getGameReviews | games/{id}/any/reviews | id int | N | ||
getGameReviews | games/{id}/{machine}/reviews | id int
machine str |
N | ||
getGameSummary | contents/games | machines str | N | ||
getGameUserReviews | games/{id}/{machine}/reviews/users | id int
machine str |
page int
perPage int |
N | |
getGameVideos | games/{id}/{machine}/videos | id int
machine str |
page int
perPage int |
N | |
getGameWikis | games/{id}/{machine}/wikis | id int
machine str |
page int
perPage int |
N | |
getHeadlineList | contents/trending | machines str
page int perPage int |
If-None-Match str | N | |
getHighTechSummary | contents/hightech | machines str | N | ||
getLightGame | games/{id}/{machine}/light | id int
machine str |
N | ||
getNews | contents/{id} | id int | N | ||
getNewsHighTech | contents/hightech | page int
perPage int |
If-None-Match str | N | |
getPageContents | accounts/{accountId}/page/contents | accountId str | page int
perPage int |
N | |
getPageReviews | accounts/{accountId}/page/reviews | accountId str | page int
perPage int |
N | |
getProfile | accounts/{accountId}/profile | accountId str | N | ||
getProfilePage | accounts/{accountId}/page | accountId str | N | ||
getRelatedNews | contents/{id}/news | id int | page int
perPage int |
N | |
getRelatedVideos | contents/{id}/videos | id int | page int
perPage int |
N | |
getRelatedWikis | contents/{id}/wikis | id int | page int
perPage int |
N | |
getSpecificNews | rétro-ingénierie à faire | N | |||
getStores | games/{id}/{machine}/stores | id int
machine str |
N | ||
getTechList | contents/hightech | page int
perPage int |
If-None-Match str | N | |
getTopWikis | contents/wikis | If-None-Match str | N | ||
getTopsComments | contents/{contentID}/comments/tops | contentID str | N | ||
getVideo | videos/{id} | id int | N | ||
getVideoList | rétro-ingénierie à faire | categories str
chronicles str machines str types str page int perPage int |
If-None-Match str | N | |
getVideosSummary | contents/videos | machines str | N | ||
search | rétro-ingénierie à faire | q str | N | ||
searchArticles | search/articles | q str
page int perPage int |
N | ||
searchAutocomplete | search/games/autocomplete | q str | N | ||
searchGames | search/games | q str
page int perPage int |
N | ||
searchNews | search/news | q str
page int perPage int |
N | ||
searchVideos | search/videos | q str
page int perPage int |
N | ||
searchWikis | search/wikis | q str
page int perPage int |
N | ||
sponso | general/nativeads | If-None-Match str | N |
NOM | URL | PARAMS | BODY | T |
---|---|---|---|---|
saveDescription | accounts/me/profile/description | rétro-ingénierie à faire | N | |
saveExcludedMachines | accounts/me/profile/excluded-machines | "machines" : [1, 2, 3, 4] // id des machines | N | |
saveMachines | accounts/me/profile/machines | "machines" : [1, 2, 3, 4] // id des machines | N | |
updateComment | contents/{contentID}/comments/{commentID} | contentID str
commentID str |
"content": "Super jeu !" | N |
uploadAvatar | accounts/me/avatar | rétro-ingénierie à faire | N | |
uploadCover | accounts/me/cover | rétro-ingénierie à faire | N |
NOM | URL | PARAMS | T |
---|---|---|---|
deleteComment | contents/{contentID}/comments/{commentID} | contentID str
commentID str |
N |
deleteCommentVote | contents/{contentID}/comments/{commentID}/vote | contentID str
commentID str |
N |
NOM | URL | PARAMS | T |
---|---|---|---|
deleteFavorisForum | accounts/{accountId}/favorites/forums | accountId str | N |
deleteFavorisGames | accounts/{accountId}/favorites/games | accountId str | N |
deleteFavorisTopics | accounts/{accountId}/favorites/topics | accountId str | N |
Rétro-ingénierie de l'API
Pour connaître les endpoints de l'API, il faut décompiler l'appli JVC.
- Décompresser l'APK de l'application avec 7zip/Winrar/etc.
- Utiliser un décompilateur Dex vers Java, comme Jadx .
Une fois le code Java disponible, on peut ouvrir l'interface com.jeuxvideo.api.web.JvApiService, qui contient tous les endpoints. L'appli utilise le bibliothèque Retrofit 2.x pour gérer l'API, on peut facilement parcourir la documentation de cette bibliothèque pour découvrir ce qu'il faut faire comme requête aux différentes URL de l'API.
La classe com.jeuxvideo.utils.ApiLogin (nom de la classe donné arbitrairement car perdu lors de la compilation), permet de déduire qu'il faut mettre dans le header de la requête à l'API Jvc-Authorization : header ainsi que l'algorithme permettant de trouver ce qu'il faut mettre à la place de header.
Classe PHP exploitant l'API
-> https://pastebin.com/LWNDQDKy
Cette classe est incomplète et sera possiblement rendue obsolète dans le temps.
Ancienne API
Le contenu qui va suivre concerne l'ancienne API, qui n'existe plus. Si quelqu'un est courageux pour de nouveau documenter l'API actuelle de JV, nous en serions tous ravis.
Identification
L'API utilise le nom de domaine ws.jeuxvideo.com. Pour y accéder, il faut utiliser un des identifiants ci-dessous (authentification HTTP basique).
Tous ces identifiants fonctionnement actuellement, et je n'ai pas repéré de page semblant afficher un comportement différent selon.
Utilisateur | Mot de passe | |
---|---|---|
Android 1.0 | appandr | e32!cdf |
Android 2.0.3 | app_and_gnw | FC?4554? |
Android 2.5 | app_and_ms | D9!mVR4c |
Android MP | app_ag_jvmp | LXnb45=d# |
Android Tab | nex12sz | GT4!V2cT |
iPhone | app_ios_nw | W!P45-R |
iPad | ip45de | XpD5!FT |
L'API est accessible en HTTP et en HTTPS, préférez la version HTTPS !
Utilisation
Connexion
Pour vous connecter, utilisez la page mon_compte/connexion.php.
Voici les paramètres à envoyer (GET ou POST) :
Paramètre | Valeur |
---|---|
newnom | Le pseudo de l'utilisateur. |
stamp | Le timestamp (le nombre de secondes depuis le 1er janvier 1970) à l'heure où la requête est envoyée. |
hash | Un hash MD5 sous la forme : md5(pseudo + motDePasse + "OpX234" + stamp) OpX234 est un salt. |
Vous renconterez potentiellement une erreur vous demandant de remplir un captcha, avec un lien vers l'image, et une balise params_form, qu'il faudra ajouter aux paramètres de la première requête, ainsi que le paramètre code avec la valeur du captcha.
Important : n'ouvrez pas le lien du captcha dans votre navigateur si vous êtes connecté à votre compte JVC ; un captcha différent est renvoyé selon la présence du cookie coniunctio (qui ne doit PAS être présent pour afficher un captcha de l'API, sinon vous aurez systématiquement une erreur de captcha invalide).
En réponse, vous recevez plusieurs informations présentes dans la CDV, mais surtout le cookie coniunctio, que vous devrez utiliser pour poster sur les forums et utiliser les messages privés.
Pour information, coniunctio signifie logjvnew à l'envers, et c'est le cookie de session de JVC dont le nom a subi plusieurs transformations au fil des années.
Pour le renvoi de mot de passe, utilisez cette URL (en remplaçant Cisla par le pseudo ou bien l'adresse e-mail) :
https://ws.jeuxvideo.com/cgi-bin/passperdu_ws.cgi?email_pseudo=Cisla
Jeux, astuces, news...
URL | Description |
---|---|
00.machines_version.xml 00.version_tablette.xml |
Dernière version de l'application, informations sur la publicité, liste des consoles |
01.flux_jeux_nouveautes.xml 01.flux_jeux_prochainement.xml |
Listes de jeux |
01.jeux/21963.xml 01.jeux/details/21963.xml 01.jeux/videos/21963.xml 01.jeux/screen/21963.xml 03.preview/43689.xml 03.test_complet/9813.xml 01.jeux/news/21963.xml 05.jeu_astuce/41030.xml 05.astuce/33258.xml 01.jeux/screen_ast/38024.xml |
Informations sur le jeu (le nombre correspond à l'id) |
03.dossier/18270.xml 03.dossier/18270/1.xml |
Un dossier : 18270 est l'id du dossier, 1 est la page (si vous n'en mettez pas, vous avez le sommaire) |
02.flux_news.xml 02.flux_news-4.xml |
La liste des dernières news. Dans le deuxième exemple, en ajoutant le nombre 4, vous retournez 4 jours en arrière (ça peut aller jusqu'à 9) |
03.flux_articles_tests.xml 03.flux_articles_tests-4.xml 03.flux_articles_apercus.xml 03.flux_articles_apercus-4.xml 03.flux_articles_dossier.xml 03.flux_articles_dossier-4.xml 04.flux_videos_cliq.xml 04.flux_videos_cliq-4.xml 04.flux_videos_gaming.xml 04.flux_videos_gaming-4.xml 04.flux_videos_autres.xml 04.flux_videos_autres-4.xml 05.flux_astuces.xml 05.flux_astuces-4.xml 04.flux_videos_chroniques.xml 04.flux_videos_chroniques-4.xml 04.flux_toutes_les_videos.xml 04.flux_toutes_les_videos-4.xml |
Même chose pour les derniers articles, tests, astuces et aperçus |
02.news/1234.xml 02.news_screen/1234.xml |
Voir une news (le nombre correspond à l'id) |
ean.php?ean=0045496830144 | Voir le jeu associé au code-barre (EAN) 0045496830144 |
forums_index.xml | Liste des forums généraux |
search_n/mario search/mario search_sug/mario search_forums/mario search_forums_sug/mario |
Effectuer une recherche dans le nom des jeux ou des forums |
tab_suggest_blocs.xml tab_suggest_forums.xml |
À compléter |
cgi-bin/liste.cgi | À compléter |
Forums
Pour les forums, les URL sont les mêmes que pour JVC, à part que :
- Le .htm est transformé en .xml
- Le www.jeuxvideo.com est remplacé par un ws.jeuxvideo.com
- La chaîne de caractères à la fin de l'URL (comme blabla-15-18-ans ou nom-du-topic) est remplacée par un 0 (sauf pour la recherche).
Par exemple :
http://www.jeuxvideo.com/forums/0-50-0-1-0-1-0-blabla-15-18-ans.htm
Devient :
https://ws.jeuxvideo.com/forums/0-50-0-1-0-1-0-0.xml
Exemples d'URL :
URL | Description |
---|---|
https://ws.jeuxvideo.com/forums/0-50-0-1-0-1-0-0.xml | La liste des sujets |
https://ws.jeuxvideo.com/forums/0-50-0-1-0-1-2-cactus.xml | Rechercher « cactus » dans le titre des topics |
https://ws.jeuxvideo.com/forums/1-50-1-1-0-1-0-0.xml | Un topic |
https://ws.jeuxvideo.com/forums/3-50-0-1-0-1-0-0.xml | Formulaire pour créer un topic |
https://ws.jeuxvideo.com/forums/3-50-128244545-1-0-1-0-0.xml | 10 derniers messages d'un topic + formulaire |
https://ws.jeuxvideo.com/forums/5-50-128244545-1-0-1-0-0.xml | Formulaire de réponse à un topic |
https://ws.jeuxvideo.com/cgi-bin/jvforums/forums.cgi | Envoyer un message (avec les données POST) |
https://ws.jeuxvideo.com/profil/cisla.xml | Voir une CDV |
Pour envoyer un message ou créer un topic : aux données de formulaires qui vous sont communiquées dans la balise params_form, vous devez ajouter le paramètre yournewmessage qui contient le message et newsujet qui contient le titre du topic (si vous créez un nouveau topic). Vous devez ensuite attendre une seconde avant d'envoyer les données POST à la page forums.cgi. En cas de captcha à gérer, vous devez répéter l'opération à partir des informations qu'on vous envoie en réponse, avec la solution du captcha en paramètre code.
Vous devez être connecté (envoyer le cookie coniunctio) pour récupérer et envoyer un formulaire.
Le même formulaire peut aussi bien être envoyé au forums.cgi de ws.jeuxvideo.com qu'à celui de www.jeuxvideo.com, ce qui vous permet de choisir entre apparaître « via mobile » ou non. Les données POST à envoyer sont donc les mêmes sur toutes les versions de JVC.
Messages privés
L'id de l'utilisateur mentionnée ci-dessous correspond à la partie du cookie coniunctio qui se trouve avant le premier "$".
Une fois connecté, vous devez envoyer le cookie coniunctio à chaque requête.
URL | Description |
---|---|
jvmp.xml | Dernière version de l'application, liste des consoles et des smileys, lien vers la charte, pub activée ou non |
messages-prives/connexion_ws.php | Les paramètres sont les mêmes que pour la connexion depuis mon_compte/connexion.php, décrite plus haut. Cependant, la réponse XML contient quelques informations supplémentaires à propos des MP. |
messages-prives/boite-reception_ws.php | Permet de connaître le contenu de la boîte de réception. Paramètre à envoyer :
|
messages-prives/envoyes_ws.php | Permet de connaître la liste des messages envoyés. Paramètre à envoyer :
|
messages-prives/message_ws.php | Permet de lire le contenu d'un message privé. Paramètres à envoyer :
|
messages-prives/nouveau_ws.php | Permet d'envoyer un nouveau message privé. Paramètres à envoyer :
Il se peut également que vous ayez à gérer un code de confirmation. |
messages-prives/repondre_ws.php | Permet de répondre à un message privé. Paramètres à envoyer :
Il se peut également que vous ayez à gérer un code de confirmation. |
messages-prives/suggest_pseudo_ws.php | Liste quelques pseudos qui commencent par ce que l'utilisateur est en train de taper. Paramètres à envoyer :
|
messages-prives/indesirable_ws.php | Liste les utilisateurs ajoutés en indésirable. Paramètres à envoyer :
|
messages-prives/add_indesirable_ws.php | Permet d'ajouter un utilisateur dans les indésirables. Certaines données nécessaires pour former la requête doivent être récupérés avec info_alerte_ws.php. Paramètres à envoyer :
|
messages-prives/del_indesirable_ws.php | Permet d'enlever un utilisateur des indésirables. Paramètres à envoyer :
|
messages-prives/info_alerte_ws.php | Permet de connaître les informations qui permettront de faire une DDB ou une mise en indésirable sur un message. Paramètres à envoyer :
|
messages-prives/alerte_ws.php | Permet d'effectuer une DDB (ce qui est inutile, étant donné qu'elles ne sont jamais traitées). Certaines données nécessaires pour former la requête doivent être récupérés avec info_alerte_ws.php. Paramètres à envoyer :
|
messages-prives/connexion_valid_ws.php | Permet d'afficher le nombre de messages non-lus ainsi que l'URL de l'avatar. Paramètres à envoyer :
|
messages-prives/add_destinataire_ws.php | Permet d'ajouter un destinataire à un message privé. Paramètres à envoyer :
|
messages-prives/del_message_ws.php | Permet de supprimer un message privé. Paramètres à envoyer :
|
Reverse-engineering
Décompilation
Cette section concerne la décompilation de l'application Android de JVC sous Linux.
Pour décompiler l'application JVC, commencez par récupérer le fichier APK ici (version 2.5). Ensuite, décompressez-le avec 7-Zip :
$ 7z x com.jeuxvideo-2.5.apk
Puis, transformez le .dex en .jar à l'aide de l'utilitaire dex2jar :
$ dex2jar classes.dex
Ensuite, vous pouvez ouvrir le .jar dans jd-gui, qui s'occupera de décompiler les fichiers :
$ jd-gui classes-dex2jar.jar
Déobfuscation
En parcourant le code source, vous verrez des choses de ce genre à la place des chaînes de caractères :
this.g.getString(2131230723)
Cela correspond à des chaînes de caractères stockées dans un fichier séparé, resources.arsc. Pour en extraire le contenu, nous allons utiliser l'utilitaire apktool :
$ apktool d com.jeuxvideo-2.5.apk strings
Ensuite, vous pourrez trouver dans le fichier strings/res/values/strings.xml la liste des chaînes de caractères associées à leurs variables, et dans strings/res/values/public.xml, la liste des variables associées aux nombres (en hexadécimal) comme 2131230723 que vous voyez dans le code décompilé. Ce n'est pas très pratique mais je n'ai pas trouvé d'outil qui modifie directement le code décompilé pour y intégrer les valeurs du resources.arsc (mais je n'ai pas beaucoup cherché non plus).
Ce n'est pas tout. À partir de la version 2.0.3 de l'application JVC, et pour toutes les version de l'application JVC MP, vous pourrez également voir dans le fichier strings.xml des variables telles que :
<string name="md5_a">290B2FB20CFD682C120BBBFFFE5928D9</string>
Ces chaînes de caractères (des URL et quelques salts) sont obfusquées. Après avoir lu un peu de code, j'ai trouvé comment les restituer. Voici un bout de Python qui montre comment faire :
from Crypto.Cipher import AES from passlib.utils.pbkdf2 import pbkdf2 cle = 'package android.content' cle = AES.new(pbkdf2(cle, cle, 10, 128/8, 'hmac-sha1')) string = '290B2FB20CFD682C120BBBFFFE5928D9' string = cle.decrypt(string.decode('hex')) print repr(string[:-ord(string[-1])])
Modifiez la clé selon l'application que vous décompilez:
- Pour l'application Jeuxvideo.com (version >= 2.0.3), c'est package com.jeuxvideo.activity
- Pour l'application Jeuxvideo.com (version >= 2.5), c'est package android.content
- Pour l'application Jeuxvideo.com MP (version >= 1.0), c'est package com.jeuxvideomp.activity
L'application pour tablettes n'est pas concernée par ce mécanisme d'obfuscation.
Liens externes
- API sur Wikipédia
- Lien du topic sur JVC pour poser vos questions
- L'application Android
- L'application Android des MP
- L'application iPhone
- L'application iPhone des MP
- L'APK de l'application Android :
- L'APK de l'application Android des MP :
- L'APK de l'application Android tablette :
Références