Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion _includes/includes/ui/downloads.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,12 @@ function downloadLargeCTA($product, $platform, $tier, $filepattern) {
$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 <<<END
<div class="download-cta-big selected" id="cta-big-Windows" data-url='$host/$platform/$tier/{$versions->$platform->$tier->version}/$file' data-version='{$versions->$platform->$tier->version}'>
<div class="download-cta-big selected" id="cta-big-Windows" data-url='$downloadUrl' data-version='{$versions->$platform->$tier->version}'>
<div class="download-stable-email">
<h3>$product {$versions->$platform->$tier->version}</h3>
<p>Released: {$fileData->date}</p>
Expand Down
7 changes: 7 additions & 0 deletions go/.htaccess
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ RewriteRule "^package/download/(keyboard/)?([^/]+)$" "package/download.php?type=
# keyboard/id/share
RedirectMatch "/go/keyboard/([^/?]+)/share$" "/keyboards/share/$1"

#
# go/app/download
#

# download-app?url=...
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# download-app?url=...
# go/app/download/<product>/<version>/<tier>?url=https://downloads.keyman.com/...

RewriteRule "^app/download/([^/?]+)/([^/?]+)/(.*)" "app/download.php?product=$1&version=$2&tier=$3" [END,QSA]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a url parameter? (download.php l.19)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QSA means url (and any other query params) will be passed to the rewritten script


#
# Non-app-specific endpoints
#
Expand Down
99 changes: 99 additions & 0 deletions go/app/download.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php
declare(strict_types=1);

namespace Keyman\Site\com\keyman;

require __DIR__ . '/../../_includes/autoload.php';

const DEBUG=0;

use Keyman\Site\com\keyman\KeymanComSentry;
use Keyman\Site\com\keyman\Validation;
use Keyman\Site\Common\KeymanHosts;
use Keyman\Site\Common\JsonApiFailure;

$env = getenv();
KeymanComSentry::init();

AppDownloadPage::redirect_to_file(
isset($_REQUEST['url']) ? $_REQUEST['url'] : null,
isset($_REQUEST['product']) ? $_REQUEST['product'] : null,
isset($_REQUEST['version']) ? $_REQUEST['version'] : null,
isset($_REQUEST['tier']) ? $_REQUEST['tier'] : null,
// TODO: should we? or just leave it encoded in URL for now?
// isset($_REQUEST['bcp47']) ? $_REQUEST['bcp47'] : null,
// isset($_REQUEST['update']) ? $_REQUEST['update'] : null
);

class AppDownloadPage {

public static function redirect_to_file($url, $product, $version, $tier) {
if(empty($url)) {
JsonApiFailure::InvalidParameters("url");
}

if(empty($product)) {
$product = 'unknown';
}

if(empty($version)) {
$version = '0.0';
}

if(empty($tier)) {
$tier = 'stable';
}

$tier = Validation::validate_tier($tier, 'stable');

$url_e = htmlentities($url);

if(DEBUG) {
header('Content-Type: text/plain');
}

if(KeymanHosts::Instance()->Tier() !== KeymanHosts::TIER_TEST) {
self::report_app_download_event($product, $version, $tier);

if(DEBUG) {
echo "\n\nLocation: $url\n";
exit;
}

// We don't do a redirect for Test tier because a test instance of the
// downloads server is not available and so it gives us an error
header("HTTP/1.1 302 Found");
header("Cache-Control: no-store");
header("Location: $url");
}

echo "<a href='$url_e'>Download Link</a>";
}

private static function report_app_download_event($product, $version, $tier) {
global $env;
$url = KeymanHosts::Instance()->SERVER_api_keyman_com . "/app-downloads-increment/".rawurlencode($product).
"/".rawurlencode($version)."/".rawurlencode($tier);

if(KeymanHosts::Instance()->Tier() !== KeymanHosts::TIER_TEST) {
if(KeymanHosts::Instance()->Tier() === KeymanHosts::TIER_DEVELOPMENT)
$key = 'local';
else
$key = $env['API_KEYMAN_COM_INCREMENT_DOWNLOAD_KEY'];

$c = curl_init($url);
curl_setopt($c, CURLOPT_HEADER, 0);
curl_setopt($c, CURLOPT_POSTFIELDS, 'key='.rawurlencode($key));
curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($c, CURLOPT_USERAGENT , "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)");
$data = curl_exec($c);
curl_close($c);

if(DEBUG) {
var_dump("app-downloads-increment ($url):",$data);
}
} else
$data = TRUE;
return $data !== FALSE;
}
}
45 changes: 0 additions & 45 deletions go/package/download.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,48 +117,3 @@ private static function report_download_event($id, $platform, $tier, $bcp47, $up
return $data !== FALSE;
}
}

/**
* Returns a GUIDv4 string
*
* Uses the best cryptographically secure method
* for all supported pltforms with fallback to an older,
* less secure version.
* https://www.php.net/manual/en/function.com-create-guid.php#119168
*
* @param bool $trim
* @return string
*/
function GUIDv4 ($trim = true)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function was unused, just noticed when cloning into go/app/download.php

{
// Windows
if (function_exists('com_create_guid') === true) {
if ($trim === true)
return trim(com_create_guid(), '{}');
else
return com_create_guid();
}

// OSX/Linux
if (function_exists('openssl_random_pseudo_bytes') === true) {
$data = openssl_random_pseudo_bytes(16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

// Fallback (PHP 4.2+)
mt_srand((double)microtime() * 10000);
$charid = strtolower(md5(uniqid(rand(), true)));
$hyphen = chr(45); // "-"
$lbrace = $trim ? "" : chr(123); // "{"
$rbrace = $trim ? "" : chr(125); // "}"
$guidv4 = $lbrace.
substr($charid, 0, 8).$hyphen.
substr($charid, 8, 4).$hyphen.
substr($charid, 12, 4).$hyphen.
substr($charid, 16, 4).$hyphen.
substr($charid, 20, 12).
$rbrace;
return $guidv4;
}
3 changes: 2 additions & 1 deletion keyboards/install.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,12 @@ protected static function WriteWindowsBoxes() {

// This maps to buildStandardWindowsDownloadUrl in install.js (which we don't use here for those
// few users who have JS disabled -- although this is not really a tested/supported scenario)
$downloadLink = KeymanHosts::Instance()->downloads_keyman_com .
$downloadServerLink = KeymanHosts::Instance()->downloads_keyman_com .
"/windows/{$hu['tier']}/{$hu['version']}/keyman-setup" .
self::BOOTSTRAP_SEPARATOR . "{$hu['id']}" .
(empty($hu['bcp47']) ? "" : ".{$hu['bcp47']}") .
".exe";
$downloadLink = "/go/app/download/windows/{$hu['version']}/{$hu['tier']}?url=".rawurlencode($downloadServerLink);

$helpLink = KeymanHosts::Instance()->help_keyman_com . "/products/windows/current-version/start/download-and-install-keyman";

Expand Down