api/get.php

506 lines
16 KiB
PHP
Raw Normal View History

2017-09-22 21:24:31 +02:00
<?php
/*
Copyright 2021 whatever127
2017-09-22 21:24:31 +02:00
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
require_once dirname(__FILE__).'/shared/main.php';
require_once dirname(__FILE__).'/shared/requests.php';
require_once dirname(__FILE__).'/shared/packs.php';
/*
$updateId = Update Identifier
$usePack = Desired language
$desiredEdition = Desired edition
$requestType = 0 = uncached request,;
1 = use cache if available;
2 = offline information retrieval
*/
2018-11-16 17:59:48 +01:00
function uupGetFiles(
$updateId = 'c2a1d787-647b-486d-b264-f90f3782cdc6',
$usePack = 0,
$desiredEdition = 0,
$requestType = 0
2018-11-16 17:59:48 +01:00
) {
uupApiPrintBrand();
2017-09-22 21:24:31 +02:00
2019-09-14 17:26:57 +02:00
if(!$updateId) {
return array('error' => 'UNSPECIFIED_UPDATE');
}
if(!uupApiCheckUpdateId($updateId)) {
return array('error' => 'INCORRECT_ID');
}
$info = @file_get_contents('fileinfo/'.$updateId.'.json');
if(empty($info)) {
$info = array(
'ring' => 'WIF',
'flight' => 'Active',
'arch' => 'amd64',
'checkBuild' => '10.0.16251.0',
'sku' => '48',
'files' => array(),
);
} else {
$info = json_decode($info, true);
}
if(isset($info['build'])) {
$build = explode('.', $info['build']);
$build = $build[0];
} else {
$build = 9841;
}
if(!isset($info['sku'])) {
$info['sku'] = 48;
}
2017-09-22 21:24:31 +02:00
if($usePack) {
$genPack = uupGetGenPacks($build, $info['arch'], $updateId);
if(empty($genPack)) return array('error' => 'UNSUPPORTED_COMBINATION');
if(!isset($genPack[$usePack])) {
2017-09-22 21:24:31 +02:00
return array('error' => 'UNSUPPORTED_LANG');
}
}
if(!is_array($desiredEdition)) {
$desiredEdition = strtoupper($desiredEdition);
$fileListSource = $desiredEdition;
2017-09-22 21:24:31 +02:00
switch($desiredEdition) {
case '0':
if($usePack) {
$fileListSource = 'GENERATEDPACKS';
2021-02-06 14:26:21 +01:00
$filesPacksList = array();
foreach($genPack[$usePack] as $val) {
foreach($val as $package) {
2021-02-06 14:26:21 +01:00
$filesPacksList[] = $package;
}
}
2021-02-06 14:26:21 +01:00
array_unique($filesPacksList);
sort($filesPacksList);
}
break;
case 'WUBFILE': break;
case 'UPDATEONLY': break;
2017-09-22 21:24:31 +02:00
default:
if(!isset($genPack[$usePack][$desiredEdition])) {
return array('error' => 'UNSUPPORTED_COMBINATION');
}
2017-09-22 21:24:31 +02:00
2021-02-06 14:26:21 +01:00
$filesPacksList = $genPack[$usePack][$desiredEdition];
$fileListSource = 'GENERATEDPACKS';
break;
}
} else {
$fileListSource = 'GENERATEDPACKS';
2021-02-06 14:26:21 +01:00
$filesPacksList = array();
foreach($desiredEdition as $edition) {
$edition = strtoupper($edition);
if(!isset($genPack[$usePack][$edition])) {
return array('error' => 'UNSUPPORTED_COMBINATION');
}
2021-02-06 14:26:21 +01:00
$filesPacksList = array_merge($filesPacksList, $genPack[$usePack][$edition]);
}
2017-10-16 18:03:26 +02:00
}
2017-10-23 22:53:33 +02:00
$rev = 1;
if(preg_match('/_rev\./', $updateId)) {
$rev = preg_replace('/.*_rev\./', '', $updateId);
$updateId = preg_replace('/_rev\..*/', '', $updateId);
}
2021-02-06 14:26:21 +01:00
$updateSku = $info['sku'];
2018-10-11 21:48:46 +02:00
$updateArch = (isset($info['arch'])) ? $info['arch'] : 'UNKNOWN';
$updateBuild = (isset($info['build'])) ? $info['build'] : 'UNKNOWN';
$updateName = (isset($info['title'])) ? $info['title'] : 'Unknown update: '.$updateId;
2021-09-19 15:58:48 +02:00
$sha256capable = isset($info['sha256ready']);
2018-10-11 21:48:46 +02:00
2021-02-06 14:26:21 +01:00
if(isset($info['releasetype'])) {
$type = $info['releasetype'];
}
if(!isset($type)) {
$type = 'Production';
if($updateSku == 189 || $updateSku == 135) foreach($info['files'] as $val) {
if(preg_match('/NonProductionFM/i', $val['name'])) $type = 'Test';
}
}
if($requestType < 2) {
2021-02-06 14:26:21 +01:00
$filesInfoList = uupGetOnlineFiles($updateId, $rev, $info, $requestType, $type);
} else {
2021-02-06 14:26:21 +01:00
$filesInfoList = uupGetOfflineFiles($info);
}
2021-02-06 14:26:21 +01:00
if(isset($filesInfoList['error'])) {
return $filesInfoList;
}
2021-09-19 15:58:48 +02:00
if(!$sha256capable) {
$baseless = preg_grep('/^baseless_|-baseless\....$/i', array_keys($filesInfoList));
foreach($baseless as $val) {
if(isset($filesInfoList[$val])) unset($filesInfoList[$val]);
}
2021-09-19 15:58:48 +02:00
$diffs = preg_grep('/.*_Diffs_.*|.*_Forward_CompDB_.*|\.cbsu\.cab$/i', array_keys($filesInfoList));
foreach($diffs as $val) {
if(isset($filesInfoList[$val])) unset($filesInfoList[$val]);
}
2021-09-19 15:58:48 +02:00
$psf = array_keys($filesInfoList);
$psf = preg_grep('/\.psf$/i', $psf);
2021-09-19 15:58:48 +02:00
$psfk = preg_grep('/Windows10\.0-KB.*/i', $psf);
$psfk = preg_grep('/.*-EXPRESS|.*-baseless/i', $psfk, PREG_GREP_INVERT);
if($build > 21380) foreach($psfk as $key => $val) {
if(isset($psf[$key])) unset($psf[$key]);
}
unset($psfk);
2021-09-19 15:58:48 +02:00
$removeFiles = array();
foreach($psf as $val) {
$name = preg_replace('/\.psf$/i', '', $val);
$removeFiles[] = $name;
unset($filesInfoList[$val]);
}
unset($index, $name, $psf);
2021-09-19 15:58:48 +02:00
$temp = preg_grep('/'.$updateArch.'_.*|arm64\.arm_.*|arm64\.x86_.*/i', $removeFiles);
foreach($temp as $key => $val) {
2021-02-06 14:26:21 +01:00
if(isset($filesInfoList[$val.'.cab'])) unset($filesInfoList[$val.'.cab']);
2021-09-19 15:58:48 +02:00
unset($removeFiles[$key]);
}
unset($temp);
foreach($removeFiles as $val) {
if(isset($filesInfoList[$val.'.esd'])) {
if(isset($filesInfoList[$val.'.cab'])) unset($filesInfoList[$val.'.cab']);
}
}
2021-09-19 15:58:48 +02:00
unset($removeFiles);
}
2021-02-06 14:26:21 +01:00
$filesInfoKeys = array_keys($filesInfoList);
switch($fileListSource) {
case 'UPDATEONLY':
$skipPackBuild = 1;
2021-09-24 13:41:53 +02:00
$removeFiles = preg_grep('/Windows10\.0-KB.*-EXPRESS|Windows10\.0-KB.*-baseless|SSU-\d*?\.\d*?-.{3,5}-EXPRESS/i', $filesInfoKeys);
foreach($removeFiles as $val) {
2021-02-06 14:26:21 +01:00
if(isset($filesInfoList[$val])) unset($filesInfoList[$val]);
}
2021-02-06 14:26:21 +01:00
unset($removeFiles);
2021-02-06 14:26:21 +01:00
$filesInfoKeys = array_keys($filesInfoList);
2021-09-24 13:41:53 +02:00
$filesInfoKeys = preg_grep('/Windows10\.0-KB|SSU-\d*?\.\d*?-.*?\.cab/i', $filesInfoKeys);
2021-02-06 14:26:21 +01:00
if(count($filesInfoKeys) == 0) {
return array('error' => 'NOT_CUMULATIVE_UPDATE');
}
break;
case 'WUBFILE':
$skipPackBuild = 1;
2021-02-06 14:26:21 +01:00
$filesInfoKeys = preg_grep('/WindowsUpdateBox.exe/i', $filesInfoKeys);
break;
}
2021-02-06 14:26:21 +01:00
$uupCleanFunc = 'uupCleanName';
if($updateSku == 189) $uupCleanFunc = 'uupCleanWCOS';
if($updateSku == 135) $uupCleanFunc = 'uupCleanHolo';
if($fileListSource == 'GENERATEDPACKS') {
2021-09-24 13:41:53 +02:00
$temp = preg_grep('/Windows10\.0-KB.*-EXPRESS|Windows10\.0-KB.*-baseless|SSU-\d*?\.\d*?-.{3,5}-EXPRESS/i', $filesInfoKeys, PREG_GREP_INVERT);
$temp = preg_grep('/Windows10\.0-KB|SSU-\d*?\.\d*?-.*?\.cab/i', $temp);
2021-02-06 14:26:21 +01:00
$filesPacksList = array_merge($filesPacksList, $temp);
$newFiles = array();
2021-09-19 15:58:48 +02:00
$failedFile = false;
if($sha256capable) {
$tmp = [];
foreach($filesInfoList as $key => $val) {
$tmp[$val['sha256']] = $key;
}
2021-09-19 15:58:48 +02:00
foreach($filesPacksList as $val) {
if(isset($tmp[$val])) {
$name = $tmp[$val];
$newFiles[$name] = $filesInfoList[$name];
} else if(isset($filesInfoList[$val])) {
$name = $val;
$newFiles[$name] = $filesInfoList[$name];
} else {
$failedFile = $val;
}
}
} else {
foreach($filesPacksList as $val) {
$name = $uupCleanFunc($val);
$filesPacksKeys[] = $name;
if(isset($filesInfoList[$name])) {
$newFiles[$name] = $filesInfoList[$name];
} else {
$failedFile = $name;
}
}
}
2021-09-19 15:58:48 +02:00
if($failedFile) {
consoleLogger("Missing file: $failedFile");
2019-02-23 23:23:35 +01:00
return array('error' => 'MISSING_FILES');
}
2021-09-19 15:58:48 +02:00
$filesInfoList = $newFiles;
$filesInfoKeys = array_keys($filesInfoList);
}
2021-02-06 14:26:21 +01:00
if(empty($filesInfoKeys)) {
return array('error' => 'NO_FILES');
}
2021-02-06 14:26:21 +01:00
$filesNew = array();
foreach($filesInfoKeys as $val) {
$filesNew[$val] = $filesInfoList[$val];
}
$files = $filesNew;
ksort($files);
consoleLogger('Successfully parsed the information.');
return array(
'apiVersion' => uupApiVersion(),
'updateName' => $updateName,
'arch' => $updateArch,
'build' => $updateBuild,
2021-02-06 14:26:21 +01:00
'sku' => $updateSku,
'files' => $files,
);
}
2021-02-06 14:26:21 +01:00
function uupGetOnlineFiles($updateId, $rev, $info, $cacheRequests, $type) {
$cacheHash = hash('sha256', strtolower("api-get-${updateId}_rev.$rev"));
$cached = 0;
2018-11-16 17:59:48 +01:00
if(file_exists('cache/'.$cacheHash.'.json.gz') && $cacheRequests == 1) {
$cache = @gzdecode(@file_get_contents('cache/'.$cacheHash.'.json.gz'));
$cache = json_decode($cache, 1);
if(!empty($cache['content']) && ($cache['expires'] > time())) {
consoleLogger('Using cached response...');
$out = $cache['content'];
$fetchTime = $cache['fetchTime'];
$cached = 1;
} else {
$cached = 0;
}
unset($cache);
}
if(!$cached) {
$fetchTime = time();
consoleLogger('Fetching information from the server...');
2021-02-06 14:26:21 +01:00
$postData = composeFileGetRequest($updateId, uupDevice(), $info, $rev, $type);
$out = sendWuPostRequest('https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured', $postData);
2018-11-16 17:59:48 +01:00
consoleLogger('Information has been successfully fetched.');
}
2017-09-22 21:24:31 +02:00
consoleLogger('Parsing information...');
2018-11-16 21:29:29 +01:00
$xmlOut = @simplexml_load_string($out);
if($xmlOut === false) {
@unlink('cache/'.$cacheHash.'.json.gz');
return array('error' => 'XML_PARSE_ERROR');
2018-11-16 21:29:29 +01:00
}
2018-10-11 21:48:46 +02:00
$xmlBody = $xmlOut->children('s', true)->Body->children();
if(!isset($xmlBody->GetExtendedUpdateInfo2Response)) {
2017-10-01 16:06:01 +02:00
consoleLogger('An error has occurred');
2017-09-22 21:24:31 +02:00
return array('error' => 'EMPTY_FILELIST');
}
2018-10-11 21:48:46 +02:00
$getResponse = $xmlBody->GetExtendedUpdateInfo2Response;
$getResult = $getResponse->GetExtendedUpdateInfo2Result;
if(!isset($getResult->FileLocations)) {
consoleLogger('An error has occurred');
return array('error' => 'EMPTY_FILELIST');
}
2021-02-06 14:26:21 +01:00
$uupCleanFunc = 'uupCleanName';
if($info['sku'] == 189) $uupCleanFunc = 'uupCleanWCOS';
if($info['sku'] == 135) $uupCleanFunc = 'uupCleanHolo';
2021-09-19 15:58:48 +02:00
$sha256capable = isset($info['sha256ready']);
2018-10-11 21:48:46 +02:00
$fileLocations = $getResult->FileLocations;
2017-09-22 21:24:31 +02:00
$info = $info['files'];
$files = array();
2018-10-11 21:48:46 +02:00
foreach($fileLocations->FileLocation as $val) {
$sha1 = bin2hex(base64_decode((string)$val->FileDigest));
2021-09-19 15:58:48 +02:00
$sha256 = isset($info[$sha1]['sha256']) ? $info[$sha1]['sha256'] : null;
2018-10-11 21:48:46 +02:00
$url = (string)$val->Url;
2017-09-22 21:24:31 +02:00
2018-10-11 21:48:46 +02:00
preg_match('/files\/(.{8}-.{4}-.{4}-.{4}-.{12})/', $url, $guid);
$guid = $guid[1];
2017-09-22 21:24:31 +02:00
if(empty($info[$sha1]['name'])) {
$name = $guid;
$size = -1;
2017-09-22 21:24:31 +02:00
} else {
2021-02-06 14:26:21 +01:00
$name = $info[$sha1]['name'];
2017-09-22 21:24:31 +02:00
$size = $info[$sha1]['size'];
}
if(!isset($fileSizes[$name])) $fileSizes[$name] = -2;
2017-09-22 21:24:31 +02:00
if($size > $fileSizes[$name]) {
2018-10-11 21:48:46 +02:00
preg_match('/P1=(.*?)&/', $url, $expire);
if(isset($expire[0])) {
2018-10-11 21:48:46 +02:00
$expire = $expire[1];
2017-10-16 18:03:26 +02:00
}
$expire = intval($expire);
if($size < 0) {
$temp = ($expire - $fetchTime) / 600;
$size = ($temp - 1) * 31457280;
if($size < 0) $size = 0;
unset($temp);
}
$fileSizes[$name] = $size;
$temp = array();
$temp['sha1'] = $sha1;
2021-09-19 15:58:48 +02:00
$temp['sha256'] = $sha256;
$temp['size'] = $size;
$temp['url'] = $url;
$temp['uuid'] = $guid;
$temp['expire'] = $expire;
$temp['debug'] = $val->asXML();
2021-09-19 15:58:48 +02:00
if($sha256capable) {
$n = strrpos($name, '.');
if($n === false) $n = strlen($name);
$newName = substr($name, 0, $n).'_'.substr($sha1, 0, 8).substr($name, $n);
} else {
$newName = $uupCleanFunc($name);
}
$files[$newName] = $temp;
2017-09-22 21:24:31 +02:00
}
}
2021-07-01 17:58:52 +02:00
if($cacheRequests == 1 && $cached == 0) {
$cache = array(
'expires' => time()+90,
'content' => $out,
'fetchTime' => $fetchTime,
);
if(!file_exists('cache')) mkdir('cache');
@file_put_contents('cache/'.$cacheHash.'.json.gz', gzencode(json_encode($cache)."\n"));
}
return $files;
}
function uupGetOfflineFiles($info) {
if(empty($info['files'])) return array();
2021-02-06 14:26:21 +01:00
$uupCleanFunc = 'uupCleanName';
if($info['sku'] == 189) $uupCleanFunc = 'uupCleanWCOS';
if($info['sku'] == 135) $uupCleanFunc = 'uupCleanHolo';
2021-09-19 15:58:48 +02:00
$sha256capable = isset($info['sha256ready']);
consoleLogger('Parsing information...');
foreach($info['files'] as $sha1 => $val) {
$name = $val['name'];
$size = $val['size'];
2021-09-19 15:58:48 +02:00
$sha256 = isset($val['sha256']) ? $val['sha256'] : null;
if(!isset($fileSizes[$name])) $fileSizes[$name] = 0;
2017-10-16 18:03:26 +02:00
if($size > $fileSizes[$name]) {
$fileSizes[$name] = $size;
2017-10-16 18:03:26 +02:00
$temp = array();
$temp['sha1'] = $sha1;
2021-09-19 15:58:48 +02:00
$temp['sha256'] = $sha256;
$temp['size'] = $size;
$temp['url'] = null;
$temp['uuid'] = null;
$temp['expire'] = 0;
$temp['debug'] = null;
2021-09-19 15:58:48 +02:00
if($sha256capable) {
$n = strrpos($name, '.');
if($n === false) $n = strlen($name);
$newName = substr($name, 0, $n).'_'.substr($sha1, 0, 8).substr($name, $n);
} else {
$newName = $uupCleanFunc($name);
}
$files[$newName] = $temp;
}
2017-09-22 21:24:31 +02:00
}
return $files;
2017-09-22 21:24:31 +02:00
}
2019-01-31 20:17:41 +01:00
function uupCleanName($name) {
$replace = array(
'cabs_' => null,
'metadataesd_' => null,
2019-02-23 23:23:35 +01:00
'prss_signed_appx_' => null,
2019-01-31 20:17:41 +01:00
'~31bf3856ad364e35' => null,
'~~.' => '.',
'~.' => '.',
'~' => '-',
);
$name = strtr($name, 'QWERTYUIOPASDFGHJKLZXCVBNM', 'qwertyuiopasdfghjklzxcvbnm');
return strtr($name, $replace);
}
2021-02-06 14:26:21 +01:00
function uupCleanWCOS($name) {
$name = preg_replace('/^(appx)_(messaging_desktop|.*?)_/i', '$1/$2/', $name);
$name = preg_replace('/^(retail)_(.{3,5})_fre_/i', '$1/$2/fre/', $name);
return strtr($name, 'QWERTYUIOPASDFGHJKLZXCVBNM', 'qwertyuiopasdfghjklzxcvbnm');
}
function uupCleanHolo($name) {
$name = preg_replace('/^(appx)_(Cortana_WCOS|FeedbackHub_WCOS|HEVCExtension_HoloLens|MixedRealityViewer_arm64|MoviesTV_Hololens|Outlook_WindowsTeam|WinStore_HoloLens)_/i', '$1/$2/', $name);
$name = preg_replace('/^(appx)_(.*?)_/i', '$1/$2/', $name);
$name = preg_replace('/^(retail)_(.{3,5})_fre_/i', '$1/$2/fre/', $name);
return strtr($name, 'QWERTYUIOPASDFGHJKLZXCVBNM', 'qwertyuiopasdfghjklzxcvbnm');
}