version_check.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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('UCT');
  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.0.28' => [
  64. 'installed' => [
  65. 'direct_download_url' => [
  66. 'x64' => 'https://github.com/canton7/SyncTrayzor/releases/download/v1.0.28/SyncTrayzorSetup-x64.exe',
  67. 'x86' => 'https://github.com/canton7/SyncTrayzor/releases/download/v1.0.28/SyncTrayzorSetup-x86.exe',
  68. ],
  69. ],
  70. 'sha1sum_download_url' => 'https://github.com/canton7/SyncTrayzor/releases/download/v1.0.28/sha1sum.txt.asc',
  71. 'release_page_url' => 'https://github.com/canton7/SyncTrayzor/releases/tag/v1.0.28',
  72. 'release_notes' => "- Allow extra Syncthing command-line arguments to be specified (#133)\n- Fix bug which would prevent multiple logged-on users using the same SyncTrayzor installation (#148)\n- Add extra process priority options for Syncthing (other than just 'low priority') (#143)\n- Fix a couple of small crashes\n- Reduce installer/portable zip size slightly\n- Handle restart-less Folder and Device changes in Syncthing\n- Handle some edge-cases where Syncthing state changes in the middle of lots of file transfers may not be noticed\n- Fix a very rare \"Error creating the Web Proxy\" issue (#131)\n- Improve translations (#142, others)",
  73. ]
  74. ];
  75. $upgrades = [
  76. '1.0.27' => ['to' => 'latest', 'formatter' => '3'],
  77. '1.0.26' => ['to' => 'latest', 'formatter' => '3'],
  78. '1.0.25' => ['to' => 'latest', 'formatter' => '3'],
  79. '1.0.24' => ['to' => 'latest', 'formatter' => '3'],
  80. '1.0.23' => ['to' => 'latest', 'formatter' => '3'],
  81. '1.0.22' => ['to' => 'latest', 'formatter' => '2'],
  82. '1.0.21' => ['to' => 'latest', 'formatter' => '2'],
  83. '1.0.20' => ['to' => 'latest', 'formatter' => '2'],
  84. // 1.0.19 was never actually released, so no need to represent it
  85. '1.0.18' => ['to' => 'latest', 'formatter' => '2'],
  86. '1.0.17' => ['to' => 'latest', 'formatter' => '2'],
  87. '1.0.16' => ['to' => 'latest', 'formatter' => '2'],
  88. '1.0.15' => ['to' => 'latest', 'formatter' => '2'],
  89. '1.0.14' => ['to' => 'latest', 'formatter' => '2'],
  90. '1.0.13' => ['to' => 'latest', 'formatter' => '1'],
  91. '1.0.12' => ['to' => 'latest', 'formatter' => '1'],
  92. ];
  93. $response_formatters = [
  94. // 1.0.12 and 1.0.13 shouldn't download installers directly, as they doesn't know how to run them properly
  95. '1' => function($arch, $variant, $to_version, $to_version_info, $overrides)
  96. {
  97. $data = [
  98. 'version' => $to_version,
  99. 'direct_download_url' => null,
  100. 'release_page_url' => $to_version_info['release_page_url'],
  101. 'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
  102. ];
  103. return $data;
  104. },
  105. // Prior to sha1sum_download_url
  106. '2' => function($arch, $variant, $to_version, $to_version_info, $overrides)
  107. {
  108. $variant_info = isset($overrides[$variant]) ? get_with_wildcard($overrides, $variant) : get_with_wildcard($to_version_info, $variant);
  109. $data = [
  110. 'version' => $to_version,
  111. 'direct_download_url' => get_with_wildcard($variant_info['direct_download_url'], $arch),
  112. 'release_page_url' => $to_version_info['release_page_url'],
  113. 'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
  114. ];
  115. return $data;
  116. },
  117. '3' => function($arch, $variant, $to_version, $to_version_info, $overrides)
  118. {
  119. $variant_info = isset($overrides[$variant]) ? get_with_wildcard($overrides, $variant) : get_with_wildcard($to_version_info, $variant);
  120. $data = [
  121. 'version' => $to_version,
  122. 'direct_download_url' => get_with_wildcard($variant_info['direct_download_url'], $arch),
  123. 'sha1sum_download_url' => $to_version_info['sha1sum_download_url'],
  124. 'release_page_url' => $to_version_info['release_page_url'],
  125. 'release_notes' => isset($overrides['release_notes']) ? $overrides['release_notes'] : $to_version_info['release_notes'],
  126. ];
  127. return $data;
  128. },
  129. ];
  130. $error = null;
  131. $loggable_error = null;
  132. $data = null;
  133. try
  134. {
  135. $version = isset($_GET['version']) ? $_GET['version'] : null;
  136. $arch = isset($_GET['arch']) ? $_GET['arch'] : null;
  137. $variant = isset($_GET['variant']) ? $_GET['variant'] : null;
  138. if (empty($version) || empty($arch) || empty($variant))
  139. {
  140. $error = ['code' => 1, 'message' => 'version, arch, or variant not specified'];
  141. }
  142. else if (isset($upgrades[$version]))
  143. {
  144. $to_version = $upgrades[$version]['to'];
  145. if ($to_version == 'latest')
  146. $to_version = array_keys($versions)[0];
  147. $formatter = $response_formatters[$upgrades[$version]['formatter']];
  148. $overrides = isset($upgrades[$version]['overrides']) ? $upgrades[$version]['overrides'] : [];
  149. $to_version_info = $versions[$to_version];
  150. $data = $formatter($arch, $variant, $to_version, $to_version_info, $overrides);
  151. }
  152. }
  153. catch (Exception $e)
  154. {
  155. $error = ['code' => 2, 'message' => 'Unhandled error. Please try again later'];
  156. $loggable_error = $e->getMessage() . "\n" . $e->getTraceAsString();
  157. }
  158. $rsp = [];
  159. if ($data != null)
  160. $rsp['data'] = $data;
  161. if ($error != null)
  162. $rsp['error'] = $error;
  163. $output = json_encode($rsp, JSON_UNESCAPED_SLASHES | JSON_FORCE_OBJECT);
  164. $date = date('c');
  165. $log_msg = "$date\t{$_SERVER['REMOTE_ADDR']}\t$version\t$arch\t$variant\t$output\t$loggable_error\n";
  166. $fp = fopen('log.txt', 'a+');
  167. flock($fp, LOCK_EX);
  168. fputcsv($fp, [$date, $_SERVER['REMOTE_ADDR'], $version, $arch, $variant, $output, $loggable_error]);
  169. fclose($fp);
  170. echo $output;