summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README6
-rw-r--r--actions/getfile.php145
-rw-r--r--actions/newnotice.php4
-rw-r--r--actions/twitapistatuses.php7
-rw-r--r--htaccess.sample8
-rw-r--r--lib/router.php4
-rw-r--r--lib/util.php10
7 files changed, 176 insertions, 8 deletions
diff --git a/README b/README
index c98090b4b..e0d63e43c 100644
--- a/README
+++ b/README
@@ -755,6 +755,12 @@ private site, but users of the private site may be able to subscribe
to users on a remote site. (Or not... it's not well tested.) The
"proper behaviour" hasn't been defined here, so handle with care.
+If fancy URLs is enabled, access to file attachments can also be
+restricted to logged-in users only. Uncomment the appropriate rewrite
+rule in .htaccess or your server's httpd.conf. (This most likely will
+not work if you are using a virtual server for attachments, so consider
+the performance/security tradeoff.)
+
Upgrading
=========
diff --git a/actions/getfile.php b/actions/getfile.php
new file mode 100644
index 000000000..ecda34c0f
--- /dev/null
+++ b/actions/getfile.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Returns a given file attachment, allowing private sites to only allow
+ * access to file attachments after login.
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program 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
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Personal
+ * @package StatusNet
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once 'MIME/Type.php';
+
+/**
+ * Action for getting a file attachment
+ *
+ * @category Personal
+ * @package StatusNet
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class GetfileAction extends Action
+{
+ /**
+ * Path of file to return
+ */
+
+ var $path = null;
+
+ /**
+ * Get file name
+ *
+ * @param array $args $_REQUEST array
+ *
+ * @return success flag
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $filename = $this->trimmed('filename');
+ $path = null;
+
+ if ($filename) {
+ $path = common_config('attachments', 'dir') . $filename;
+ }
+
+ if (empty($path) or !file_exists($path)) {
+ $this->clientError(_('No such file.'), 404);
+ return false;
+ }
+ if (!is_readable($path)) {
+ $this->clientError(_('Cannot read file.'), 403);
+ return false;
+ }
+
+ $this->path = $path;
+ return true;
+ }
+
+ /**
+ * Is this page read-only?
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * Last-modified date for file
+ *
+ * @return int last-modified date as unix timestamp
+ */
+
+ function lastModified()
+ {
+ return filemtime($this->path);
+ }
+
+ /**
+ * etag for file
+ *
+ * This returns the same data (inode, size, mtime) as Apache would,
+ * but in decimal instead of hex.
+ *
+ * @return string etag http header
+ */
+ function etag()
+ {
+ $stat = stat($this->path);
+ return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
+ }
+
+ /**
+ * Handle input, produce output
+ *
+ * @param array $args $_REQUEST contents
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ // undo headers set by PHP sessions
+ $sec = session_cache_expire() * 60;
+ header('Expires: ' . date(DATE_RFC1123, time() + $sec));
+ header('Cache-Control: public, max-age=' . $sec);
+ header('Pragma: public');
+
+ parent::handle($args);
+
+ $path = $this->path;
+ header('Content-Type: ' . MIME_Type::autoDetect($path));
+ readfile($path);
+ }
+}
diff --git a/actions/newnotice.php b/actions/newnotice.php
index 8c0476f70..548832eca 100644
--- a/actions/newnotice.php
+++ b/actions/newnotice.php
@@ -271,7 +271,9 @@ class NewnoticeAction extends Action
common_broadcast_notice($notice);
if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
$this->elementStart('head');
$this->element('title', null, _('Notice posted'));
$this->elementEnd('head');
diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php
index 360dff27c..b0d3e584b 100644
--- a/actions/twitapistatuses.php
+++ b/actions/twitapistatuses.php
@@ -236,11 +236,8 @@ class TwitapistatusesAction extends TwitterapiAction
}
if (empty($status)) {
-
- // XXX: Note: In this case, Twitter simply returns '200 OK'
- // No error is given, but the status is not posted to the
- // user's timeline. Seems bad. Shouldn't we throw an
- // errror? -- Zach
+ $this->clientError(_('Client must provide a \'status\' parameter with a value.'),
+ $code = 403, $apidata['content-type']);
return;
} else {
diff --git a/htaccess.sample b/htaccess.sample
index 37eb8e01e..373108c81 100644
--- a/htaccess.sample
+++ b/htaccess.sample
@@ -5,6 +5,14 @@
RewriteBase /mublog/
+ # If your site is private and want access to file attachments
+ # restricted to logged-in users only, uncomment this rule.
+ #
+ # If you have a custom attachment path
+ # ($config['attachments']['path']), change "file/" to match.
+ #
+ #RewriteRule ^file/(.*) getfile/$1
+
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?p=$1 [L,QSA]
diff --git a/lib/router.php b/lib/router.php
index 5529e60ac..7455d9cf8 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -171,6 +171,10 @@ class Router
array('action' => 'attachment_thumbnail'),
array('attachment' => '[0-9]+'));
+ $m->connect('getfile/:filename',
+ array('action' => 'getfile'),
+ array('filename' => '[A-Za-z0-9._-]+'));
+
$m->connect('notice/new', array('action' => 'newnotice'));
$m->connect('notice/new?replyto=:replyto',
array('action' => 'newnotice'),
diff --git a/lib/util.php b/lib/util.php
index 047faeef0..0052090f6 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -760,12 +760,18 @@ function common_path($relative, $ssl=false)
if (is_string(common_config('site', 'sslserver')) &&
mb_strlen(common_config('site', 'sslserver')) > 0) {
$serverpart = common_config('site', 'sslserver');
- } else {
+ } else if (common_config('site', 'server')) {
$serverpart = common_config('site', 'server');
+ } else {
+ common_log(LOG_ERR, 'Site Sever not configured, unable to determine site name.');
}
} else {
$proto = 'http';
- $serverpart = common_config('site', 'server');
+ if (common_config('site', 'server')) {
+ $serverpart = common_config('site', 'server');
+ } else {
+ common_log(LOG_ERR, 'Site Sever not configured, unable to determine site name.');
+ }
}
return $proto.'://'.$serverpart.'/'.$pathpart.$relative;