public

Secures attachments for messages in BuddyPress when using the BuddyPress Message Attachment plugin, by only service the file to users that are part of the thread the file is attached to.

  • Download Gist
bp-message-attachment-secure.php
PHP
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
<?php
/**
* This gist secures attachments for messages in BuddyPress when
* using the BuddyPress Message Attachment plugin, by only serving
* the file to users that are part of the thread the file is attached
* to.
*
* =Usage=
* Add the functions in this file to your theme's functions.php or
* wherever you want it. Then add the following rewrite rule to your
* .htaccess file:
*
* RewriteRule ^wp\-content/uploads/message\-attachements/(.*) /?bp_message_attachment=$1 [R,L]
*
* (if you use a custom uploads folder, replace wp-content/uploads with
* the path to your upload folder)
*
*
* Inspired by http://dev.commons.gc.cuny.edu/2011/02/05/hardening-buddypress-group-documents/
* See http://wordpress.org/extend/plugins/buddypress-message-attachment/
*
* @version 0.1
* @author mike@trenvo.com
*/
 
function bp_catch_msg_att_request() {
global $wpdb, $bp;
 
/**
* Internal error handler
* @param str $msg
*/
function _att_request_handle_error( $msg ) {
global $bp;
 
$messages_url = trailingslashit( bp_loggedin_user_domain() . $bp->messages->slug );
bp_core_add_message( $msg, 'error' );
bp_core_redirect( $messages_url );
exit;
}
 
// Check if we need to load
if ( ! isset ( $_GET['bp_message_attachment'] ) || empty ( $_GET['bp_message_attachment'] ) )
return;
 
/**
* Get conversation by attachment
*/
 
/** 1. Get attachment post **/
$file_path = $_GET['bp_message_attachment'];
 
// Make sure the file path doesn't start with a slash
if ( substr ( $file_path, 0, 1 ) == '/' )
$file_path = substr ( $file_path, 1 );
 
$upload_dir = wp_upload_dir();
 
// Stitch together the url of the attachment
$file_url = trailingslashit( $upload_dir['url'] ) . 'message-attachements/' . $file_path;
 
$args = array (
"meta_key" => "bp_msgat_attachement_url",
"meta_value" => $file_url,
"post_type" => "messageattachements"
);
$attachment_post = current ( get_posts ( $args ) );
if ( ! $attachment_post )
return _att_request_handle_error( __( 'You requested a file that does not exist.', 'bp-msgat' ) );
 
$file_name = $attachment_post->post_title;
 
/** 2. Get the thread **/
$message_id = get_post_meta ( $attachment_post->ID, 'bp_msgat_message_id', true );
$thread_id = current ( explode ( "=", $message_id) );
 
/**
* Check if the current user is part of the conversation
*/
 
// Get the thread recipients
$recipients = array();
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d", $thread_id ) );
 
foreach ( (array) $results as $recipient )
$recipients[] = $recipient->user_id;
$recipients = array_unique( $recipients );
 
// Check if the current user is in the recipient list
$current_user = get_current_user_id();
if ( ! in_array ( $current_user, $recipients ) )
return _att_request_handle_error( __( 'You do not have access to this file.', 'bp-msgat' ) );
 
/**
* We're through! Let's serve the user the attachment
*/
$attachment_path = $upload_dir['path'] . '/message-attachements/' . $file_path;
 
if ( file_exists( $attachment_path ) ) {
$mime_type = mime_content_type( $attachment_path );
$file_size = filesize( $attachment_path );
 
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Pragma: hack");
 
header("Content-Type: $mime_type; name='" . $file_name . "'");
header("Content-Length: " . $file_size );
 
header('Content-Disposition: attachment; filename="' . $file_name . '"');
header("Content-Transfer-Encoding: binary");
ob_clean();
flush();
readfile( $attachment_path );
die();
 
} else {
// File does not exist anymore
return _att_request_handle_error( __( 'An error has occurred, we could not find your file anymore.', 'bp-msgat' ) );
}
}
add_filter( 'wp', 'bp_catch_msg_att_request', 1 );
 
// http://www.php.net/manual/en/function.mime-content-type.php#87856
if(!function_exists('mime_content_type')) {
 
function mime_content_type($filename) {
 
$mime_types = array(
 
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'php' => 'text/html',
'css' => 'text/css',
'js' => 'application/javascript',
'json' => 'application/json',
'xml' => 'application/xml',
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
 
// images
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
 
// archives
'zip' => 'application/zip',
'rar' => 'application/x-rar-compressed',
'exe' => 'application/x-msdownload',
'msi' => 'application/x-msdownload',
'cab' => 'application/vnd.ms-cab-compressed',
 
// audio/video
'mp3' => 'audio/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
 
// adobe
'pdf' => 'application/pdf',
'psd' => 'image/vnd.adobe.photoshop',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
 
// ms office
'doc' => 'application/msword',
'rtf' => 'application/rtf',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
 
// open office
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
);
 
$ext = strtolower(array_pop(explode('.',$filename)));
if (array_key_exists($ext, $mime_types)) {
return $mime_types[$ext];
}
elseif (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
}
else {
return 'application/octet-stream';
}
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.