From 3855dc9ac43c52a348cb8e054b485d14f338c482 Mon Sep 17 00:00:00 2001 From: orin Date: Sat, 21 Oct 2023 02:34:51 +0200 Subject: [PATCH] Rewrite WU requests and cookie handling --- .gitignore | 1 - fetchupd.php | 10 +++++--- get.php | 12 +++++++-- readme.md | 2 ++ shared/auths.php | 44 ++++++++++++++++++++++++-------- shared/main.php | 2 +- shared/requests.php | 10 +++++--- shared/utils.php | 62 +++++++++++++++++++++++---------------------- 8 files changed, 93 insertions(+), 50 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 9353dda..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -shared/cookie.json diff --git a/fetchupd.php b/fetchupd.php index df3b841..78f0bc0 100644 --- a/fetchupd.php +++ b/fetchupd.php @@ -102,10 +102,14 @@ function uupFetchUpd( if($fromCache !== false) return $fromCache; consoleLogger('Fetching information from the server...'); - $postData = composeFetchUpdRequest(uupDevice(), uupEncryptedData(), $arch, $flight, $ring, $build, $sku, $type); - $out = sendWuPostRequest('https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx', $postData); + $composerArgs = [$arch, $flight, $ring, $build, $sku, $type]; + $out = sendWuPostRequestHelper('client', 'composeFetchUpdRequest', $composerArgs); + if($out['error'] != 200) { + consoleLogger('The request has failed'); + return array('error' => 'WU_REQUEST_FAILED'); + } - $out = html_entity_decode($out); + $out = html_entity_decode($out['out']); consoleLogger('Information has been successfully fetched.'); preg_match_all('/.*?<\/UpdateInfo>/', $out, $updateInfos); diff --git a/get.php b/get.php index f3d0780..1a0e7b8 100644 --- a/get.php +++ b/get.php @@ -395,8 +395,16 @@ function uupGetOnlineFiles($updateId, $rev, $info, $cacheRequests, $type) { } else { $fetchTime = time(); consoleLogger('Fetching information from the server...'); - $postData = composeFileGetRequest($updateId, uupDevice(), $info, $rev, $type); - $out = sendWuPostRequest('https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured', $postData); + + $composerArgs = [$updateId, $info, $rev, $type]; + $out = sendWuPostRequestHelper('clientSecured', 'composeFileGetRequest', $composerArgs); + + if($out['error'] != 200) { + consoleLogger('The request has failed'); + return array('error' => 'WU_REQUEST_FAILED'); + } + + $out = $out['out']; consoleLogger('Information has been successfully fetched.'); } diff --git a/readme.md b/readme.md index b02c1b2..c1cd7d8 100644 --- a/readme.md +++ b/readme.md @@ -132,6 +132,7 @@ Parameters: - ILLEGAL_MINOR - NO_UPDATE_FOUND - EMPTY_FILELIST + - WU_REQUEST_FAILED **get.php** - UNSUPPORTED_LANG @@ -142,6 +143,7 @@ Parameters: - MISSING_FILES - NO_FILES - XML_PARSE_ERROR + - WU_REQUEST_FAILED **listeditions.php** - UNSUPPORTED_LANG diff --git a/shared/auths.php b/shared/auths.php index 6e7e67d..c1a154f 100644 --- a/shared/auths.php +++ b/shared/auths.php @@ -25,19 +25,43 @@ function uupDevice() { return base64_encode(chunk_split($data, 1, "\0")); } +function uupSaveCookieFromResponse($out) { + $outDecoded = html_entity_decode($out); + preg_match('/.*?<\/NewCookie>|.*?<\/GetCookieResult>/', $outDecoded, $cookieData); + + if(empty($cookieData)) + return false; + + preg_match('/.*<\/Expiration>/', $cookieData[0], $expirationDate); + preg_match('/.*<\/EncryptedData>/', $cookieData[0], $encryptedData); + + $expirationDate = preg_replace('/|<\/Expiration>/', '', $expirationDate[0]); + $encryptedData = preg_replace('/|<\/EncryptedData>/', '', $encryptedData[0]); + + $cookieData = array( + 'expirationDate' => $expirationDate, + 'encryptedData' => $encryptedData, + ); + + $cookieStorage = new UupDumpCache('WuRequestCookie', false); + $cookieStorage->put($cookieData, false); + + return $cookieData; +} + +function uupInvalidateCookie() { + $cookieStorage = new UupDumpCache('WuRequestCookie', false); + $cookieInfo = $cookieStorage->delete(); +} + function uupEncryptedData() { - $cookieInfo = @file_get_contents(dirname(__FILE__).'/cookie.json'); - $cookieInfo = json_decode($cookieInfo, 1); + $cookieStorage = new UupDumpCache('WuRequestCookie', false); + $cookieInfo = $cookieStorage->get(); if(empty($cookieInfo)) { - $postData = composeGetCookieRequest(uupDevice()); - sendWuPostRequest('https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx', $postData); - - $encData = uupEncryptedData(); - } else { - $encData = $cookieInfo['encryptedData']; + $data = sendWuPostRequestHelper('client', 'composeGetCookieRequest', [], false); + $cookieInfo = uupSaveCookieFromResponse($data['out']); } - return $encData; + return $cookieInfo['encryptedData']; } -?> diff --git a/shared/main.php b/shared/main.php index adb9cd9..254418e 100644 --- a/shared/main.php +++ b/shared/main.php @@ -16,7 +16,7 @@ limitations under the License. */ function uupApiVersion() { - return '1.40.3'; + return '1.41.0'; } require_once dirname(__FILE__).'/auths.php'; diff --git a/shared/requests.php b/shared/requests.php index 30093d5..269fab0 100644 --- a/shared/requests.php +++ b/shared/requests.php @@ -298,7 +298,8 @@ function branchFromBuild($build) { } // Composes POST data for gathering list of urls for download -function composeFileGetRequest($updateId, $device, $info, $rev = 1, $type = 'Production') { +function composeFileGetRequest($updateId, $info, $rev = 1, $type = 'Production') { + $device = uupDevice(); $uuid = genUUID(); $createdTime = time(); @@ -359,7 +360,9 @@ XML; } // Composes POST data for fetching the latest update information from Windows Update -function composeFetchUpdRequest($device, $encData, $arch, $flight, $ring, $build, $sku = 48, $type = 'Production') { +function composeFetchUpdRequest($arch, $flight, $ring, $build, $sku = 48, $type = 'Production') { + $device = uupDevice(); + $encData = uupEncryptedData(); $uuid = genUUID(); $createdTime = time(); @@ -585,7 +588,8 @@ XML; } // Composes POST data for Get Cookie request -function composeGetCookieRequest($device) { +function composeGetCookieRequest() { + $device = uupDevice(); $uuid = genUUID(); $createdTime = time(); diff --git a/shared/utils.php b/shared/utils.php index a7f43eb..5707c38 100644 --- a/shared/utils.php +++ b/shared/utils.php @@ -51,7 +51,7 @@ function genUUID() { ); } -function sendWuPostRequest($url, $postData) { +function sendWuPostRequestInternal($url, $postData, $saveCookie = true) { $req = curl_init($url); $proxy = uupDumpApiGetConfig(); @@ -77,38 +77,40 @@ function sendWuPostRequest($url, $postData) { curl_close($req); - /* - Replace an expired cookie with a new one by replacing it in existing - postData. This has to be done this way, because handling it properly would - most likely require a rewrite of half of the project. - */ - if($error == 500 && preg_match('/(ConfigChanged|CookieExpired)<\/ErrorCode>/', $out)) { - $oldCookie = uupEncryptedData(); - @unlink(dirname(__FILE__).'/cookie.json'); - $postData = str_replace($oldCookie, uupEncryptedData(), $postData); + if($saveCookie === true) + uupSaveCookieFromResponse($out); - return sendWuPostRequest($url, $postData); + return [ + 'error' => $error, + 'out' => $out + ]; +} + +function sendWuPostRequest($url, $postData) { + return sendWuPostRequestInternal($url, $postData)['out']; +} + +function sendWuPostRequestHelper( + $endpoint, + $postComposer, + $postComposerArgs, + $saveCookie = true +) { + $endpoints = [ + 'client' => 'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx', + 'clientSecured' => 'https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured' + ]; + + $postData = call_user_func_array($postComposer, $postComposerArgs); + $data = sendWuPostRequestInternal($endpoints[$endpoint], $postData, $saveCookie); + + if($data['error'] == 500 && preg_match('/(ConfigChanged|CookieExpired|InvalidCookie)<\/ErrorCode>/', $data['out'])) { + uupInvalidateCookie(); + $postData = call_user_func_array($postComposer, $postComposerArgs); + return sendWuPostRequestInternal($endpoints[$endpoint], $postData, $saveCookie); } - $outDecoded = html_entity_decode($out); - preg_match('/.*?<\/NewCookie>|.*?<\/GetCookieResult>/', $outDecoded, $cookieData); - - if(!empty($cookieData)) { - preg_match('/.*<\/Expiration>/', $cookieData[0], $expirationDate); - preg_match('/.*<\/EncryptedData>/', $cookieData[0], $encryptedData); - - $expirationDate = preg_replace('/|<\/Expiration>/', '', $expirationDate[0]); - $encryptedData = preg_replace('/|<\/EncryptedData>/', '', $encryptedData[0]); - - $fileData = array( - 'expirationDate' => $expirationDate, - 'encryptedData' => $encryptedData, - ); - - @file_put_contents(dirname(__FILE__).'/cookie.json', json_encode($fileData)); - } - - return $out; + return $data; } function consoleLogger($message, $showTime = 1) {