aboutsummaryrefslogtreecommitdiffstats
path: root/mod/getfile.php
blob: 16392f8ddf3a715f75e21788c67e8de9e220d0bc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?php

/**
 * module: getfile
 * 
 * used for synchronising files and photos across clones
 * 
 * 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,
 * 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 
 * the SSL traffic fast enough. The amount of time slop is configurable but defaults
 * to 3 minutes.
 * 
 */



require_once('include/Contact.php');

function getfile_post(&$a) {

	$hash = $_POST['hash'];
	$time = $_POST['time'];
	$sig = $_POST['signature'];
	$resource = $_POST['resource'];
	$revision = intval($_POST['revision']);

	if(! $hash)
		killme();

	$channel = channelx_by_hash($hash);

	if((! $channel) || (! $time) || (! $sig))
		killme();

	$slop = intval(get_pconfig($channel['channel_id'],'system','getfile_time_slop'));
	if($slop < 1)
		$slop = 3;

	$d1 = datetime_convert('UTC','UTC',"now + $slop minutes");
	$d2 = datetime_convert('UTC','UTC',"now - $slop minutes");	

	if(($time > d1) || ($time < d2)) {
		logger('time outside allowable range');
		killme();
	}

	if(! rsa_verify($hash . '.' . $time,base64url_decode($sig),$channel['channel_pubkey'])) {
		logger('verify failed.');
		killme();
	}


	$r = attach_by_hash($resource,$revision);

	if(! $r['success']) {
		notice( $r['message'] . EOL);
		return;
	}
	

	$unsafe_types = array('text/html','text/css','application/javascript');

	if(in_array($r['data']['filetype'],$unsafe_types)) {
			header('Content-type: text/plain');
	}
	else {
		header('Content-type: ' . $r['data']['filetype']);
	}

	header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"');
	if(intval($r['data']['os_storage'])) {
		$fname = dbunescbin($r['data']['data']);
		if(strpos($fname,'store') !== false)
			$istream = fopen($fname,'rb');
		else
			$istream = fopen('store/' . $channel['channel_address'] . '/' . $fname,'rb');
		$ostream = fopen('php://output','wb');
		if($istream && $ostream) {
			pipe_streams($istream,$ostream);
			fclose($istream);
			fclose($ostream);
		}
	}
	else
		echo dbunescbin($r['data']['data']);
	killme();



}