Skip to content

Instantly share code, notes, and snippets.

@mgmartel
Created February 14, 2013 20:17
Show Gist options
  • Save mgmartel/4956003 to your computer and use it in GitHub Desktop.
Save mgmartel/4956003 to your computer and use it in GitHub Desktop.
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.
<?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';
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment