streams/Code/Module/Getfile.php

129 lines
3.9 KiB
PHP
Raw Normal View History

2016-04-19 03:38:38 +00:00
<?php
2021-12-03 03:01:39 +00:00
2022-02-16 04:08:28 +00:00
namespace Code\Module;
2016-04-19 03:38:38 +00:00
2022-02-16 04:08:28 +00:00
use Code\Web\Controller;
use Code\Web\HTTPSig;
use Code\Lib\Channel;
use Code\Storage\Stdio;
2016-04-19 03:38:38 +00:00
/**
* module: getfile
2021-12-03 03:01:39 +00:00
*
2016-04-19 03:38:38 +00:00
* used for synchronising files and photos across clones
2021-12-03 03:01:39 +00:00
*
2016-04-19 03:38:38 +00:00
* The site initiating the file operation will send a sync packet to known clones.
* They will respond by building the DB structures they require, then will provide a
* post request to this site to grab the file data. This is sent as a stream direct to
* disk at the other end, avoiding memory issues.
*
* Since magic-auth cannot easily be used by the CURL process at the other end,
2021-12-03 03:01:39 +00:00
* we will require a signed request which includes a timestamp. This should not be
* used without SSL and is potentially vulnerable to replay if an attacker decrypts
2016-04-19 03:38:38 +00:00
* the SSL traffic fast enough. The amount of time slop is configurable but defaults
* to 3 minutes.
2021-12-03 03:01:39 +00:00
*
2016-04-19 03:38:38 +00:00
*/
require_once('include/attach.php');
2021-12-02 23:02:31 +00:00
class Getfile extends Controller
{
public function post()
{
$header_verified = false;
logger('getfile_args: ' . print_r($_POST, true));
$hash = $_POST['hash'];
$resource = $_POST['resource'];
$revision = intval($_POST['revision']);
$resolution = ((isset($_POST['resolution'])) ? intval($_POST['resolution']) : (-1));
if (argc() > 1) {
$verify_hash = argv(1);
if ($verify_hash !== $resource) {
logger('resource mismatch');
killme();
}
}
if (!$hash) {
logger('no sender hash');
killme();
}
foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $head) {
2022-09-04 01:35:50 +00:00
if (array_key_exists($head, $_SERVER) && str_starts_with(trim($_SERVER[$head]), 'Signature')) {
2021-12-02 23:02:31 +00:00
if ($head !== 'HTTP_AUTHORIZATION') {
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
continue;
}
$verified = HTTPSig::verify('');
if ($verified && $verified['header_signed'] && $verified['header_valid']) {
2023-01-26 20:43:23 +00:00
$r = hubloc_id_addr_query($verified['signer']);
if ($r) {
foreach($r as $hub) {
if ($hub['hubloc_hash'] === $hash) {
$header_verified = true;
break;
}
}
2021-12-02 23:02:31 +00:00
}
}
}
}
if (!$header_verified) {
http_status_exit(403, 'Permission denied');
}
2022-01-25 01:26:12 +00:00
$channel = Channel::from_hash($hash);
2021-12-02 23:02:31 +00:00
if (!$channel) {
logger('error: missing info');
killme();
}
if ($resolution > 0) {
2021-12-03 03:01:39 +00:00
$r = q(
"select * from photo where resource_id = '%s' and uid = %d and imgscale = %d limit 1",
2021-12-02 23:02:31 +00:00
dbesc($resource),
intval($channel['channel_id']),
intval($resolution)
);
if ($r) {
header('Content-type: ' . $r[0]['mimetype']);
if (intval($r[0]['os_storage'])) {
Stdio::fcopy(dbunescbin($r[0]['content']), 'php://output');
2021-12-02 23:02:31 +00:00
} else {
echo dbunescbin($r[0]['content']);
}
}
killme();
}
$r = attach_by_hash($resource, $channel['channel_hash'], $revision);
if (!$r['success']) {
logger('attach_by_hash failed: ' . $r['message']);
notice($r['message'] . EOL);
return;
}
header('Content-type: ' . $r['data']['filetype']);
header('Content-Disposition: attachment; filename="' . $r['data']['filename'] . '"');
if (intval($r['data']['os_storage'])) {
2022-06-24 21:08:59 +00:00
Stdio::fcopy(dbunescbin($r['data']['content']),'php://output');
2021-12-02 23:02:31 +00:00
} else {
echo dbunescbin($r['data']['content']);
}
killme();
}
2016-04-19 03:38:38 +00:00
}