diff --git a/_content/10/index.php b/_content/10/index.php index 5d4a2eca..ef5321a8 100644 --- a/_content/10/index.php +++ b/_content/10/index.php @@ -1,12 +1,12 @@

What's New in Keyman Desktop 10 for Windows?

@@ -58,7 +58,7 @@ supports Unicode 11.0 and BCP 47 language identifiers. Desktop 10 also includes additional user interface for Turkish.

What's New in Keyman 10 for macOS?

@@ -68,7 +68,7 @@ and easily install keyboard packages by double-clicking the kmp file.

Keyman for Android is also available on the Play Store.

@@ -92,7 +92,7 @@ Swift 4.0 app.

What's New in KeymanWeb 10?

@@ -104,7 +104,7 @@

Developer Software

Keyman Developer 10 allows you to create diff --git a/_content/11/index.php b/_content/11/index.php index 1482d7ac..7c88ab19 100644 --- a/_content/11/index.php +++ b/_content/11/index.php @@ -1,11 +1,11 @@

What's New in Keyman 11 for macOS?

@@ -92,7 +92,7 @@
  • Keyman for Android is available on the Play Store.
  • @@ -122,7 +122,7 @@ @@ -131,7 +131,7 @@

    Developer Software

    What's new in Keyman Developer 11?

    diff --git a/_content/12/index.php b/_content/12/index.php index 91db9d88..a784b67d 100644 --- a/_content/12/index.php +++ b/_content/12/index.php @@ -1,8 +1,8 @@ User Software

    What's New in Keyman 14 for Windows?

    @@ -98,7 +99,7 @@

    What's New in Keyman 14 for macOS?

    @@ -144,7 +145,7 @@ @@ -188,7 +189,7 @@

    What's New in KeymanWeb 14?

    @@ -208,7 +209,7 @@

    Developer Software

    What's new in Keyman Developer 14?

    diff --git a/_content/15/index.php b/_content/15/index.php index 79fc5237..89bc2e9c 100644 --- a/_content/15/index.php +++ b/_content/15/index.php @@ -1,11 +1,12 @@ User Software

    What's New in Keyman 15 for Windows?

    @@ -111,7 +112,7 @@

    What's New in Keyman 15 for macOS?

    @@ -146,7 +147,7 @@ @@ -184,7 +185,7 @@

    What's New in KeymanWeb 15?

    @@ -201,7 +202,7 @@

    Developer Software

    What's new in Keyman Developer 15?

    diff --git a/_content/developer/download.php b/_content/developer/download.php index 55853861..2b391220 100644 --- a/_content/developer/download.php +++ b/_content/developer/download.php @@ -1,8 +1,8 @@

    Keyman Developer Command Line Tools

    diff --git a/_content/downloads/_downloads.php b/_content/downloads/_downloads.php index 2bd26a40..4a7d7b89 100644 --- a/_content/downloads/_downloads.php +++ b/_content/downloads/_downloads.php @@ -1,7 +1,9 @@

    @@ -20,10 +22,10 @@


    diff --git a/_content/downloads/all-versions/index.php b/_content/downloads/all-versions/index.php index d286c7b4..1d3063ad 100644 --- a/_content/downloads/all-versions/index.php +++ b/_content/downloads/all-versions/index.php @@ -1,6 +1,5 @@ Keyman version history (all products)

    Keyman for Linux

    @@ -64,8 +65,8 @@ sudo apt install keyman onboard-keyman

    You can also sign up to access pre-release versions through Google Play.

    @@ -74,10 +75,10 @@

    Please register for the pre-release versions through the links below for Keyman beta or alpha pre-releases on your iOS device. This will grant access to the respective app version through Apple's TestFlight app, which facilitates direct installation on iOS devices.

    - + diff --git a/_content/downloads/releases/_version_downloads.php b/_content/downloads/releases/_version_downloads.php index 75c43bae..a32a5508 100644 --- a/_content/downloads/releases/_version_downloads.php +++ b/_content/downloads/releases/_version_downloads.php @@ -1,9 +1,10 @@

    Keyman for Android is also available on the Play Store.

    @@ -144,10 +145,10 @@ function array_key_first(array $arr) {

    Products for Software Developers


    diff --git a/_content/linux/download.php b/_content/linux/download.php index fb5facfa..d66ccfc2 100644 --- a/_content/linux/download.php +++ b/_content/linux/download.php @@ -1,7 +1,5 @@ Install directly from keyman.com

    Install via Homebrew

    diff --git a/_content/windows/download.php b/_content/windows/download.php index 8a408255..f77e301d 100644 --- a/_content/windows/download.php +++ b/_content/windows/download.php @@ -1,6 +1,7 @@ diff --git a/_content/windows/keyboards.php b/_content/windows/keyboards.php index ccf5f082..eb5c8e13 100644 --- a/_content/windows/keyboards.php +++ b/_content/windows/keyboards.php @@ -1,6 +1,5 @@ = 1073741824) { + $bytes = number_format($bytes / 1073741824, 2) . ' GB'; + } elseif ($bytes >= 1048576) { + $bytes = number_format($bytes / 1048576, 2) . ' MB'; + } elseif ($bytes >= 1024) { + $bytes = number_format($bytes / 1024, 2) . ' KB'; + } elseif ($bytes > 1) { + $bytes = $bytes . ' bytes'; + } elseif ($bytes == 1) { + $bytes = $bytes . ' byte'; + } else { + $bytes = '0 bytes'; + } + + return $bytes; + } + + private static function filenamePatterns($target, $tier) { + global $versions; + switch($target) { + case 'android': return 'keyman-$version.apk'; + case 'android-engine': return 'keyman-engine-android-$version.zip'; + case 'developer': return ['keymandeveloper-$version.exe', 'kmcomp-$version.zip']; + case 'ios': return 'keyman-ios-$version.ipa'; // not currently used + case 'ios-engine': return 'keyman-engine-ios-$version.zip'; + case 'linux': return ''; // not currently used + case 'mac': return ['keyman-$version.pkg','keyman-$version.dmg']; + case 'web': return 'keymanweb-$version.zip'; + case 'windows': return ['keyman-$version.exe', 'keymandesktop-$version.exe']; + default: throw new Exception("Invalid target $target"); + } + } + + private static function productName($target) { + switch($target) { + case 'android': return 'product_android'; + case 'android-engine': return 'product_engine_android'; + case 'developer': return 'product_developer'; + case 'ios': return 'product_ios'; // not currently used + case 'ios-engine': return 'product_engine_ios'; + case 'linux': return 'product_linux'; // not currently used + case 'mac': return 'product_macos'; // note mismatched platform name + case 'web': return 'product_keymanweb'; // note mismatched platform name + case 'windows': return 'product_windows'; + default: throw new Exception("Invalid target $target"); + } + } + + private static function title($target) { + switch($target) { + case 'android': return 'Keyman for Android'; + case 'android-engine': return 'Keyman Engine for Android'; + case 'developer': return 'Keyman Developer'; + case 'ios': return 'Keyman for iPhone and iPad'; // not currently used + case 'ios-engine': return 'Keyman Engine for iPhone and iPad'; + case 'linux': return 'Keyman for Linux'; // not currently used + case 'mac': return 'Keyman for mac'; + case 'web': return 'KeymanWeb'; + case 'windows': return 'Keyman for Windows'; + default: throw new Exception("Invalid target $target"); + } + } + + + public static function downloadSection($platform, $tiers = '', $target = '') { + + if($target == '') $target = $platform; + + echo sprintf("

    %s

    \n\n", + $target, _m_Downloads(DownloadUI::productName($target))); + $tiers = explode(' ',$tiers); + foreach($tiers as $tier) { + $filepatterns = DownloadUI::filenamePatterns($target, $tier); + echo DownloadUI::downloadLinks($platform, $tier, $filepatterns); + } + } + + private static function downloadLinks($platform, $tier, $filepatterns) { + global $versions; + $product = DownloadUI::productName($platform); + echo sprintf("

    %s

    \n
    \n", + KeymanHosts::Instance()->downloads_keyman_com, $platform, $tier, + _m_Downloads('all_product_releases', _m_Downloads($product), _m_Downloads($tier))); + } + + public static function downloadLargeCTA($platform, $tier) { + global $versions; + + if(empty($versions)) return false; + + $found = false; + + $filepatterns = DownloadUI::filenamePatterns($platform, $tier); + $title = DownloadUI::title($platform); + // CTA only supports the first download (which will typically be the right one?) + if(!is_array($filepatterns)) $filepatterns = [$filepatterns]; + foreach($filepatterns as $filepattern) { + $file = str_replace('$version', $versions->$platform->$tier->version, $filepattern); + $file = str_replace('$tier', $tier, $file); + + if(empty($versions->$platform->$tier->files->$file)) { + continue; + } + + $found = true; + + $fileData = $versions->$platform->$tier->files->$file; + $fileSize = DownloadUI::formatSizeUnits($fileData->size); + $host = KeymanHosts::Instance()->downloads_keyman_com; + $downloadSiteUrl = "$host/$platform/$tier/{$versions->$platform->$tier->version}/$file"; + $downloadUrl = htmlentities("/go/app/download/$platform/{$versions->$platform->$tier->version}/$tier?url=". + rawurlencode($downloadSiteUrl)); + + echo << +
    +

    $title {$versions->$platform->$tier->version}

    +

    Released: {$fileData->date}

    +

    Size: $fileSize

    +
    +
    +

    Download Now

    +
    +
    + +END; + } + + if(!$found) { + echo "

    No downloads found for $title.

    "; + return false; + } + } + + public static function iosTestflightTable() { + $testflight = 'https://itunes.apple.com/us/app/testflight/id899247664?mt=8'; + $testflight_beta_signup = 'https://testflight.apple.com/join/9W4XIoxQ'; + $testflight_alpha_signup = 'https://testflight.apple.com/join/vnCV2EiH'; + $testflightTable_cdn = cdn('img/testflight-64x64.png'); + $testflight_about = 'https://developer.apple.com/testflight/testers/'; + $testflightTable = << + Available through TestFlight + TestFlight app in the App Store + Sign up here for beta-only Keyman access. + Sign up for here alpha-only Keyman access. + +END; + return $testflightTable; + } + + } +?> \ No newline at end of file diff --git a/_includes/2020/KeymanDownloadVersions.php b/_includes/2020/KeymanDownloadVersions.php deleted file mode 100644 index 550c5616..00000000 --- a/_includes/2020/KeymanDownloadVersions.php +++ /dev/null @@ -1,41 +0,0 @@ - 'keyman-(\d+\.\d+\.\d+)\.apk', // Generally, use Play Store - 'ios' => 'keyman-ios-(\d+\.\d+\.\d+)\.ipa', // Always use App Store; included for completeness but not generally used - 'mac' => 'keyman-(\d+\.\d+\.\d+)\.dmg', - 'linux' => '-', // Linux distribution is multiple archives, use a package manager - 'windows' => 'keyman(desktop)?-(\d+\.\d+\.\d+(\.\d+)?).exe' - ]; - - static function getDownloadUrls() { - if(empty(self::$versions)) - self::$versions = @json_decode(Util::call_downloads_keyman_com('/api/version/2.0', 'downloads.keyman.com-api_version_2.0.json')); - return self::$versions; - } - - static function getDownloadUrl($platform, $tier = 'stable') { - $versions = self::getDownloadUrls(); - if(empty($versions->$platform->$tier)) { - return null; - } - $files = $versions->$platform->$tier; - $pattern = self::filenamePatterns[$platform]; - foreach($files->files as $name => $details) { - //echo $name; - if(preg_match("/^$pattern\$/", $name)) { - return KeymanHosts::Instance()->downloads_keyman_com . "/$platform/$tier/{$files->version}/{$name}"; - } - } - return null; - } - } diff --git a/_includes/includes/ui/downloads.php b/_includes/includes/ui/downloads.php deleted file mode 100644 index 29974e56..00000000 --- a/_includes/includes/ui/downloads.php +++ /dev/null @@ -1,116 +0,0 @@ -= 1073741824) { - $bytes = number_format($bytes / 1073741824, 2) . ' GB'; - } elseif ($bytes >= 1048576) { - $bytes = number_format($bytes / 1048576, 2) . ' MB'; - } elseif ($bytes >= 1024) { - $bytes = number_format($bytes / 1024, 2) . ' KB'; - } elseif ($bytes > 1) { - $bytes = $bytes . ' bytes'; - } elseif ($bytes == 1) { - $bytes = $bytes . ' byte'; - } else { - $bytes = '0 bytes'; - } - - return $bytes; - } - - function downloadSection($product, $platform, $filepattern, $tiers = '', $target = '') { - if($target == '') $target = $platform; - - echo sprintf("

    %s

    \n\n", - $target, _m_Downloads($product)); - $tiers = explode(' ',$tiers); - foreach($tiers as $tier) { - echo downloadLinks($product, $platform, $tier, $filepattern); - } - } - - function downloadLinks($product, $platform, $tier, $filepatterns) { - global $versions; - echo sprintf("

    %s

    \n
    \n", - KeymanHosts::Instance()->downloads_keyman_com, $platform, $tier, - _m_Downloads('all_product_releases', _m_Downloads($product), _m_Downloads($tier))); - } - - function downloadLargeCTA($product, $platform, $tier, $filepattern) { - global $versions; - - if(empty($versions)) return; - $file = str_replace('$version', $versions->$platform->$tier->version, $filepattern); - $file = str_replace('$tier', $tier, $file); - - if(empty($versions->$platform->$tier->files->$file)) { - echo "

    No downloads found for $product.

    "; - return false; - } - - $fileData = $versions->$platform->$tier->files->$file; - $fileSize = formatSizeUnits($fileData->size); - $host = KeymanHosts::Instance()->downloads_keyman_com; - $downloadSiteUrl = "$host/$platform/$tier/{$versions->$platform->$tier->version}/$file"; - $downloadUrl = htmlentities("/go/app/download/$platform/{$versions->$platform->$tier->version}/$tier?url=". - rawurlencode($downloadSiteUrl)); - - echo << -
    -

    $product {$versions->$platform->$tier->version}

    -

    Released: {$fileData->date}

    -

    Size: $fileSize

    -
    -
    -

    Download Now

    -
    -
    - -END; - } - - function iosTestflightTable() { - $testflight = 'https://itunes.apple.com/us/app/testflight/id899247664?mt=8'; - $testflight_beta_signup = 'https://testflight.apple.com/join/9W4XIoxQ'; - $testflight_alpha_signup = 'https://testflight.apple.com/join/vnCV2EiH'; - $testflightTable_cdn = cdn('img/testflight-64x64.png'); - $testflight_about = 'https://developer.apple.com/testflight/testers/'; - $testflightTable = << - Available through TestFlight - TestFlight app in the App Store - Sign up here for beta-only Keyman access. - Sign up for here alpha-only Keyman access. - -END; - return $testflightTable; - } -?> \ No newline at end of file diff --git a/_scripts/contributors/package-lock.json b/_scripts/contributors/package-lock.json index 0dc78de4..d64cc2f5 100644 --- a/_scripts/contributors/package-lock.json +++ b/_scripts/contributors/package-lock.json @@ -146,27 +146,40 @@ } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", diff --git a/go/app/download.php b/go/app/download.php index 91554bcb..5704ea9e 100644 --- a/go/app/download.php +++ b/go/app/download.php @@ -30,6 +30,12 @@ class AppDownloadPage { public static function redirect_to_file($url, $product, $version, $tier) { if(empty($url)) { JsonApiFailure::InvalidParameters("url"); + return; + } + + if(!preg_match("/^https?:\/\/downloads\\.keyman(-staging)?\\.com(\\.localhost)?\//", $url)) { + JsonApiFailure::Failure(400, JsonApiFailure::ERROR_InvalidParameters, "url parameter must start with downloads.keyman.com"); + return; } if(empty($product)) { diff --git a/go/download/_download.php b/go/download/_download.php index 5517fef5..8fc6d356 100644 --- a/go/download/_download.php +++ b/go/download/_download.php @@ -1,4 +1,24 @@ [?tier=][&version=] + * + * PRODUCT: kmcomp|keyman-developer|keyman-windows|keyman-mac + * TIER: alpha|beta|stable (default 'stable') + * VERSION: any valid version number (default to latest for tier) + * + * Redirects to the referenced executable, e.g. keyman-18.0.252.dmg for Mac. + * + * This page is referenced by Keyman Developer Server, e.g. + * /go/download/keyman-mac and by Keyman Developer kmc documentation + * /go/download/kmcomp. These paths are rewritten by .htaccess to call into + * _download.php. + */ + require_once _KEYMANCOM_INCLUDES . '/autoload.php'; use Keyman\Site\com\keyman\KeymanComSentry; use Keyman\Site\Common\KeymanHosts; @@ -34,11 +54,14 @@ $MAC_VERSION = $versions->mac->$TIER->version; } + // epic/mac-config changes the mac installer from a .dmg to .pkg, in version 19.0.291-alpha + $MAC_FILENAME = version_compare($MAC_VERSION, "19.0.291") >= 0 ? "keyman-$MAC_VERSION.pkg" : "keyman-$MAC_VERSION.dmg"; + $packages = [ "kmcomp" => ["developer", $DEVELOPER_VERSION, "kmcomp-$DEVELOPER_VERSION.zip"], "keyman-developer" => ["developer", $DEVELOPER_VERSION, "keymandeveloper-$DEVELOPER_VERSION.exe"], "keyman-windows" => ["windows", $WINDOWS_VERSION, "keyman-$WINDOWS_VERSION.exe"], - "keyman-mac" => ["mac", $MAC_VERSION, "keyman-$MAC_VERSION.dmg"] + "keyman-mac" => ["mac", $MAC_VERSION, $MAC_FILENAME], ]; if(!isset($packages[$object])) { diff --git a/go/package/download.php b/go/package/download.php index c76f09d1..eca631cb 100644 --- a/go/package/download.php +++ b/go/package/download.php @@ -35,10 +35,12 @@ public static function redirect_to_file($type, $id, $version, $platform, $tier, if($type !== 'keyboard' && $type !== 'model') { JsonApiFailure::InvalidParameters("type"); + return; } if(empty($id)) { JsonApiFailure::InvalidParameters("id, version"); + return; } if(empty($version)) { @@ -50,6 +52,7 @@ public static function redirect_to_file($type, $id, $version, $platform, $tier, if(empty($json)) { JsonApiFailure::Failure(404, JsonApiFailure::ERROR_NotFound, "$type package with id $id was not found"); + return; } $version = $json->version;