Initial Upload

This commit is contained in:
Matt Batchelder
2025-12-02 10:32:59 -05:00
commit 05ce0da296
2240 changed files with 467811 additions and 0 deletions

167
lib/Helper/LinkSigner.php Normal file
View File

@@ -0,0 +1,167 @@
<?php
/*
* Copyright (C) 2025 Xibo Signage Ltd
*
* Xibo - Digital Signage - https://xibosignage.com
*
* This file is part of Xibo.
*
* Xibo is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Xibo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Xibo\Helper;
use Xibo\Entity\Display;
/**
* S3 style links
* inspired by https://gist.github.com/kelvinmo/d78be66c4f36415a6b80
*/
class LinkSigner
{
/**
* @param \Xibo\Entity\Display $display
* @param string $encryptionKey
* @param string|null $cdnUrl
* @param $type
* @param $itemId
* @param string $storedAs
* @param string|null $fileType
* @return string
* @throws \Xibo\Support\Exception\NotFoundException
*/
public static function generateSignedLink(
Display $display,
string $encryptionKey,
?string $cdnUrl,
$type,
$itemId,
string $storedAs,
string $fileType = null,
bool $isRequestFromPwa = false,
): string {
// Start with the base url, which should correctly account for running with a CMS_ALIAS
$xmdsRoot = (new HttpsDetect())->getBaseUrl();
// PWA requests resources via `/pwa/getResource`, but the link should be served from `/xmds.php`
if ($isRequestFromPwa) {
$xmdsRoot = str_replace('/pwa/getResource', '/xmds.php', $xmdsRoot);
}
// Build the rest of the URL
$saveAsPath = $xmdsRoot
. '?file=' . $storedAs
. '&displayId=' . $display->displayId
. '&type=' . $type
. '&itemId=' . $itemId;
if ($fileType !== null) {
$saveAsPath .= '&fileType=' . $fileType;
}
$saveAsPath .= '&' . LinkSigner::getSignature(
parse_url($xmdsRoot, PHP_URL_HOST),
$storedAs,
time() + ($display->getSetting('collectionInterval', 300) * 2),
$encryptionKey,
);
// CDN?
if (!empty($cdnUrl)) {
// Serve a link to the CDN
// CDN_URL has a `?dl=` parameter on the end already, so we just encode our string and concatenate it
return 'http' . (
(
(isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https')
) ? 's' : '')
. '://' . $cdnUrl . urlencode($saveAsPath);
} else {
// Serve a HTTP link to XMDS
return $saveAsPath;
}
}
/**
* Get a S3 compatible signature
*/
public static function getSignature(
string $host,
string $uri,
int $expires,
string $secretKey,
?string $timeText = null,
?bool $isReturnSignature = false
): string {
$encodedUri = str_replace('%2F', '/', rawurlencode($uri));
$headerString = 'host:' . $host . "\n";
$signedHeadersString = 'host';
if ($timeText === null) {
$timestamp = time();
$dateText = gmdate('Ymd', $timestamp);
$timeText = $dateText . 'T000000Z';
} else {
$dateText = explode('T', $timeText)[0];
}
$algorithm = 'AWS4-HMAC-SHA256';
$scope = $dateText . '/all/s3/aws4_request';
$amzParams = [
'X-Amz-Algorithm' => $algorithm,
'X-Amz-Date' => $timeText,
'X-Amz-SignedHeaders' => $signedHeadersString
];
if ($expires > 0) {
$amzParams['X-Amz-Expires'] = $expires;
}
ksort($amzParams);
$queryStringItems = [];
foreach ($amzParams as $key => $value) {
$queryStringItems[] = rawurlencode($key) . '=' . rawurlencode($value);
}
$queryString = implode('&', $queryStringItems);
$request = 'GET' . "\n" . $encodedUri . "\n" . $queryString . "\n" . $headerString . "\n"
. $signedHeadersString . "\nUNSIGNED-PAYLOAD";
$stringToSign = $algorithm . "\n" . $timeText . "\n" . $scope . "\n" . hash('sha256', $request);
$signingKey = hash_hmac(
'sha256',
'aws4_request',
hash_hmac(
'sha256',
's3',
hash_hmac(
'sha256',
'all',
hash_hmac(
'sha256',
$dateText,
'AWS4' . $secretKey,
true
),
true
),
true
),
true
);
$signature = hash_hmac('sha256', $stringToSign, $signingKey);
return ($isReturnSignature) ? $signature : $queryString . '&X-Amz-Signature=' . $signature;
}
}