version_check.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. /**
  3. * Version upgrade path manager for SyncTrayzor
  4. *
  5. * Clients request this with their current version, arch, and variant (portable, etc)
  6. * and this gives them a version to upgrade to (if any), along with the method of
  7. * upgrading to it (manual navigation to Github release page, automatic silent upgrade,
  8. * etc).
  9. *
  10. * $versions is a record of all of the current releases, which we might want to upgrade
  11. * people to. It has the structure:
  12. * [
  13. * version => [
  14. * variant => [
  15. * 'url' => [
  16. * arch => 'url',
  17. * ...
  18. * ],
  19. * ],
  20. * ...
  21. * 'release_notes' => release_notes,
  22. * ],
  23. * ...
  24. * ]
  25. *
  26. * version: version string e.g. '1.2.3'
  27. * variant: e.g. 'portable', 'installed'. Matched against the variant provided by the
  28. * client, or '*' can be used to specify a default.
  29. * arch: e.g. 'x86', 'x64'. Matched against the arch provided by the client, or '*'
  30. * can used to specify a default.
  31. * release_notes: Release notes to display to the user.
  32. *
  33. * $upgrades is a map of old_version => new_version, and specifies the formatter to
  34. * use to communicate with old_version. It also allows various overrides to be
  35. * specified (e.g. release notes)
  36. * It has the structure:
  37. * [
  38. * old_version => ['to' => new_version, 'formatter' => formatter_version, 'overrides' => [overrides]],
  39. * ...
  40. * ]
  41. *
  42. * old_version: version being upgraded from
  43. * new_version: version to upgrade to
  44. * formatter_version: formatter version to use (in $response_formatters)
  45. * overrides: optional overrides, used by the formatter
  46. */
  47. set_error_handler('error_handler');
  48. date_default_timezone_set('UTC');
  49. header('Content-Type: application/json');
  50. function error_handler($severity, $message, $filename, $lineno)
  51. {
  52. throw new ErrorException($message, 0, $severity, $filename, $lineno);
  53. }
  54. function get_with_wildcard($src, $value, $default = null)
  55. {
  56. if (isset($src[$value]))
  57. return $src[$value];
  58. if (isset($src['*']))
  59. return $src['*'];
  60. return $default;
  61. }
  62. $versions = [
  63. '1.1.29' => [
  64. 'base_url' => 'https://github.com/canton7/SyncTrayzor/releases/download',
  65. 'installed' => [
  66. 'direct_download_url' => [
  67. 'x64' => "{base_url}/v{version}/SyncTrayzorSetup-x64.exe",
  68. 'x86' => "{base_url}/v{version}/SyncTrayzorSetup-x86.exe",
  69. ],
  70. ],
  71. 'portable' => [
  72. 'direct_download_url' => [
  73. 'x64' => "{base_url}/v{version}/SyncTrayzorPortable-x64.zip",
  74. 'x86' => "{base_url}/v{version}/SyncTrayzorPortable-x86.zip",
  75. ],
  76. ],
  77. 'sha1sum_download_url' => "{base_url}/v{version}/sha1sum.txt.asc",
  78. 'sha512sum_download_url' => "{base_url}/v{version}/sha512sum.txt.asc",
  79. 'release_page_url' => 'https://github.com/canton7/SyncTrayzor/releases/tag/v{version}',
  80. 'release_notes' => "- Don't crash in rare cases trying to detect if Intel Xe Graphics in use (#626)\n- Make it clearer that balloon settings are on the Folders tab (#613)\n- Don't show device connectivity balloons by default\n- Uninstaller: try to shut down running SyncTrayzor instances (#516)",
  81. ],
  82. '1.1.21' => [
  83. 'base_url' => 'https://synctrayzor.antonymale.co.uk/download',
  84. 'installed' => [
  85. 'direct_download_url' => [
  86. 'x64' => "{base_url}/v{version}/SyncTrayzorSetup-x64.exe",
  87. 'x86' => "{base_url}/v{version}/SyncTrayzorSetup-x86.exe",
  88. ],
  89. ],
  90. 'portable' => [
  91. 'direct_download_url' => [
  92. 'x64' => "{base_url}/v{version}/SyncTrayzorPortable-x64.zip",
  93. 'x86' => "{base_url}/v{version}/SyncTrayzorPortable-x86.zip",
  94. ],
  95. ],
  96. 'sha1sum_download_url' => "{base_url}/v{version}/sha1sum.txt.asc",
  97. 'sha512sum_download_url' => "{base_url}/v{version}/sha512sum.txt.asc",
  98. 'release_page_url' => 'https://github.com/canton7/SyncTrayzor/releases/tag/v{version}',
  99. 'release_notes' => "!!!!!\nYou must upgrade to v1.1.21 now, otherwise auto-upgrades will stop working!\n!!!!!\n\nFurther upgrades will be available once you have upgraded to v1.1.21.",
  100. ]
  101. ];
  102. $upgrades = [
  103. // Currently no need to upgrade people on 1.1.28 or 1.1.29
  104. '1.1.27' => ['to' => 'latest', 'formatter' => '5'],
  105. '1.1.26' => ['to' => 'latest', 'formatter' => '5'],
  106. '1.1.25' => ['to' => 'latest', 'formatter' => '5'],
  107. '1.1.24' => ['to' => 'latest', 'formatter' => '5'],
  108. '1.1.23' => ['to' => 'latest', 'formatter' => '5'],
  109. '1.1.22' => ['to' => 'latest', 'formatter' => '5'],
  110. '1.1.21' => ['to' => 'latest', 'formatter' => '5'],
  111. '1.1.20' => ['to' => 'latest', 'formatter' => '5'],
  112. // Github start supporting tls3 only, and versions prior to 1.1.20 didn't support this. 1.1.20 and 1.1.21 are hosted on my server. 1.1.20 can download
  113. // directly from github, but versions prior have to use my server.
  114. '1.1.19' => ['to' => '1.1.21', 'formatter' => '5'],
  115. '1.1.18' => ['to' => '1.1.21', 'formatter' => '5'],
  116. '1.1.17' => ['to' => '1.1.21', 'formatter' => '5'],
  117. '1.1.16' => ['to' => '1.1.21', 'formatter' => '5'],
  118. '1.1.15' => ['to' => '1.1.21', 'formatter' => '5'],
  119. '1.1.14' => ['to' => '1.1.21', 'formatter' => '5'],
  120. '1.1.13' => ['to' => '1.1.21', 'formatter' => '5'],
  121. '1.1.12' => ['to' => '1.1.21', 'formatter' => '5'],
  122. '1.1.11' => ['to' => '1.1.21', 'formatter' => '5'],
  123. '1.1.10' => ['to' => '1.1.21', 'formatter' => '5'],
  124. '1.1.9' => ['to' => '1.1.21', 'formatter' => '5'],
  125. '1.1.8' => ['to' => '1.1.21', 'formatter' => '5'],
  126. '1.1.7' => ['to' => '1.1.21', 'formatter' => '4'],
  127. '1.1.6' => ['to' => '1.1.21', 'formatter' => '4'],
  128. '1.1.5' => ['to' => '1.1.21', 'formatter' => '4'],
  129. '1.1.4' => ['to' => '1.1.21', 'formatter' => '4'],
  130. '1.1.3' => ['to' => '1.1.21', 'formatter' => '4'],
  131. '1.1.2' => ['to' => '1.1.21', 'formatter' => '4'],
  132. '1.1.1' => ['to' => '1.1.21', 'formatter' => '3'],
  133. '1.1.0' => ['to' => '1.1.21', 'formatter' => '3'],
  134. '1.0.32' => ['to' => '1.1.21', 'formatter' => '3'],
  135. '1.0.31' => ['to' => '1.1.21', 'formatter' => '3'],
  136. '1.0.30' => ['to' => '1.1.21', 'formatter' => '3'],
  137. '1.0.29' => ['to' => '1.1.21', 'formatter' => '3'],
  138. '1.0.28' => ['to' => '1.1.21', 'formatter' => '3'],
  139. '1.0.27' => ['to' => '1.1.21', 'formatter' => '3'],
  140. '1.0.26' => ['to' => '1.1.21', 'formatter' => '3'],
  141. '1.0.25' => ['to' => '1.1.21', 'formatter' => '3'],
  142. '1.0.24' => ['to' => '1.1.21', 'formatter' => '3'],
  143. '1.0.23' => ['to' => '1.1.21', 'formatter' => '3'],
  144. '1.0.22' => ['to' => '1.1.21', 'formatter' => '2'],
  145. '1.0.21' => ['to' => '1.1.21', 'formatter' => '2'],
  146. '1.0.20' => ['to' => '1.1.21', 'formatter' => '2'],
  147. // 1.0.19 was never actually released, so no need to represent it
  148. '1.0.18' => ['to' => '1.1.21', 'formatter' => '2'],
  149. '1.0.17' => ['to' => '1.1.21', 'formatter' => '2'],
  150. '1.0.16' => ['to' => '1.1.21', 'formatter' => '2'],
  151. '1.0.15' => ['to' => '1.1.21', 'formatter' => '2'],
  152. '1.0.14' => ['to' => '1.1.21', 'formatter' => '2'],
  153. '1.0.13' => ['to' => '1.1.21', 'formatter' => '1'],
  154. '1.0.12' => ['to' => '1.1.21', 'formatter' => '1'],
  155. ];
  156. $response_formatters = [
  157. // 1.0.12 and 1.0.13 shouldn't download installers directly, as they doesn't know how to run them properly
  158. '1' => function($arch, $variant, $to_version, $to_version_info, $overrides)
  159. {
  160. $data = [
  161. 'version' => $to_version,
  162. 'direct_download_url' => null,
  163. 'release_page_url' => $to_version_info['release_page_url'],
  164. 'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
  165. ];
  166. return $data;
  167. },
  168. // Prior to sha1sum_download_url
  169. '2' => function($arch, $variant, $to_version, $to_version_info, $overrides)
  170. {
  171. $variant_info = isset($overrides[$variant]) ? get_with_wildcard($overrides, $variant) : get_with_wildcard($to_version_info, $variant);
  172. $data = [
  173. 'version' => $to_version,
  174. 'release_page_url' => $to_version_info['release_page_url'],
  175. 'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
  176. ];
  177. if ($variant == 'installed')
  178. {
  179. $data['direct_download_url'] = get_with_wildcard($variant_info['direct_download_url'], $arch);
  180. }
  181. return $data;
  182. },
  183. // Portable versions don't know how to handle directl downloads (or it's broken...)
  184. '3' => function($arch, $variant, $to_version, $to_version_info, $overrides)
  185. {
  186. $variant_info = isset($overrides[$variant]) ? get_with_wildcard($overrides, $variant) : get_with_wildcard($to_version_info, $variant);
  187. $data = [
  188. 'version' => $to_version,
  189. 'release_page_url' => $to_version_info['release_page_url'],
  190. 'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
  191. ];
  192. if ($variant == 'installed')
  193. {
  194. $data['direct_download_url'] = get_with_wildcard($variant_info['direct_download_url'], $arch);
  195. $data['sha1sum_download_url'] = $to_version_info['sha1sum_download_url'];
  196. }
  197. return $data;
  198. },
  199. '4' => function($arch, $variant, $to_version, $to_version_info, $overrides)
  200. {
  201. $variant_info = isset($overrides[$variant]) ? get_with_wildcard($overrides, $variant) : get_with_wildcard($to_version_info, $variant);
  202. $data = [
  203. 'version' => $to_version,
  204. 'direct_download_url' => get_with_wildcard($variant_info['direct_download_url'], $arch),
  205. 'sha1sum_download_url' => $to_version_info['sha1sum_download_url'],
  206. 'release_page_url' => $to_version_info['release_page_url'],
  207. 'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
  208. ];
  209. return $data;
  210. },
  211. // Learnt about sha512sum
  212. '5' => function($arch, $variant, $to_version, $to_version_info, $overrides)
  213. {
  214. $variant_info = isset($overrides[$variant]) ? get_with_wildcard($overrides, $variant) : get_with_wildcard($to_version_info, $variant);
  215. $data = [
  216. 'version' => $to_version,
  217. 'direct_download_url' => get_with_wildcard($variant_info['direct_download_url'], $arch),
  218. 'sha512sum_download_url' => $to_version_info['sha512sum_download_url'],
  219. 'release_page_url' => $to_version_info['release_page_url'],
  220. 'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
  221. ];
  222. return $data;
  223. },
  224. ];
  225. $error = null;
  226. $loggable_error = null;
  227. $data = null;
  228. try
  229. {
  230. $version = isset($_GET['version']) ? $_GET['version'] : null;
  231. $arch = isset($_GET['arch']) ? $_GET['arch'] : null;
  232. $variant = isset($_GET['variant']) ? $_GET['variant'] : null;
  233. if (empty($version) || empty($arch) || empty($variant))
  234. {
  235. $error = ['code' => 1, 'message' => 'version, arch, or variant not specified'];
  236. }
  237. else if (isset($upgrades[$version]))
  238. {
  239. $to_version = $upgrades[$version]['to'];
  240. if ($to_version == 'latest')
  241. $to_version = array_keys($versions)[0];
  242. $formatter = $response_formatters[$upgrades[$version]['formatter']];
  243. $overrides = isset($upgrades[$version]['overrides']) ? $upgrades[$version]['overrides'] : [];
  244. $base_url = isset($overrides['base_url']) ? $overrides['base_url'] : $versions[$to_version]['base_url'];
  245. array_walk_recursive($versions[$to_version], function(&$value, $key) use ($to_version, $base_url) {
  246. $value = str_replace('{version}', $to_version, $value);
  247. $value = str_replace('{base_url}', $base_url, $value);
  248. });
  249. $to_version_info = $versions[$to_version];
  250. $data = $formatter($arch, $variant, $to_version, $to_version_info, $overrides);
  251. }
  252. }
  253. catch (Exception $e)
  254. {
  255. $error = ['code' => 2, 'message' => 'Unhandled error. Please try again later'];
  256. $loggable_error = $e->getMessage() . "\n" . $e->getTraceAsString();
  257. }
  258. $rsp = [];
  259. if ($data != null)
  260. $rsp['data'] = $data;
  261. if ($error != null)
  262. $rsp['error'] = $error;
  263. $output = json_encode($rsp, JSON_UNESCAPED_SLASHES | JSON_FORCE_OBJECT);
  264. $date = date('c');
  265. $fp = fopen('log.txt', 'a+');
  266. flock($fp, LOCK_EX);
  267. fputcsv($fp, [$date, $_SERVER['REMOTE_ADDR'], $version, $arch, $variant, $data == null ? "N" : "Y", $loggable_error]);
  268. fclose($fp);
  269. echo $output;