Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/phame/controller/blog/PhameBlogLiveController.php b/src/applications/phame/controller/blog/PhameBlogLiveController.php
index 9b3e1fec80..3fe3073c99 100644
--- a/src/applications/phame/controller/blog/PhameBlogLiveController.php
+++ b/src/applications/phame/controller/blog/PhameBlogLiveController.php
@@ -1,71 +1,74 @@
<?php
/**
* @group phame
*/
final class PhameBlogLiveController extends PhameController {
private $id;
private $more;
public function shouldAllowPublic() {
return true;
}
public function willProcessRequest(array $data) {
$this->id = idx($data, 'id');
$this->more = idx($data, 'more', '');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$blog = id(new PhameBlogQuery())
->setViewer($user)
->withIDs(array($this->id))
->executeOne();
if (!$blog) {
return new Aphront404Response();
}
if ($blog->getDomain() && ($request->getHost() != $blog->getDomain())) {
- $base_uri = 'http://'.$blog->getDomain().'/';
- if ($request->isFormPost()) {
- return id(new AphrontRedirectResponse())
- ->setURI($base_uri.$this->more);
- } else {
- // If we don't have CSRF, return a dialog instead of automatically
- // redirecting, to prevent this endpoint from serving semi-open
- // redirects.
- $dialog = id(new AphrontDialogView())
- ->setTitle(pht('Blog Moved'))
- ->setUser($user)
- ->appendChild(
- pht('This blog is now hosted at %s.',
- $base_uri))
- ->addSubmitButton(pht('Continue'));
- return id(new AphrontDialogResponse())->setDialog($dialog);
- }
+ $base_uri = $blog->getLiveURI();
+
+ // Don't redirect directly, since the domain is user-controlled and there
+ // are a bevy of security issues associated with automatic redirects to
+ // external domains.
+
+ // Previously we CSRF'd this and someone found a way to pass OAuth
+ // information through it using anchors. Just make users click a normal
+ // link so that this is no more dangerous than any other external link
+ // on the site.
+
+ $dialog = id(new AphrontDialogView())
+ ->setTitle(pht('Blog Moved'))
+ ->setUser($user)
+ ->appendParagraph(pht('This blog is now hosted here:'))
+ ->appendParagraph(
+ phutil_tag(
+ 'a',
+ array(
+ 'href' => $base_uri,
+ ),
+ $base_uri))
+ ->addCancelButton('/');
+
+ return id(new AphrontDialogResponse())->setDialog($dialog);
}
$phame_request = clone $request;
$phame_request->setPath('/'.ltrim($this->more, '/'));
- if ($blog->getDomain()) {
- $uri = new PhutilURI('http://'.$blog->getDomain().'/');
- } else {
- $uri = '/phame/live/'.$blog->getID().'/';
- $uri = PhabricatorEnv::getURI($uri);
- }
+ $uri = $blog->getLiveURI();
$skin = $blog->getSkinRenderer($phame_request);
$skin
->setBlog($blog)
- ->setBaseURI((string)$uri);
+ ->setBaseURI($uri);
$skin->willProcessRequest(array());
return $skin->processRequest();
}
}
diff --git a/src/applications/phame/controller/blog/PhameBlogViewController.php b/src/applications/phame/controller/blog/PhameBlogViewController.php
index 5bd9fabbbd..9d975055fc 100644
--- a/src/applications/phame/controller/blog/PhameBlogViewController.php
+++ b/src/applications/phame/controller/blog/PhameBlogViewController.php
@@ -1,198 +1,195 @@
<?php
/**
* @group phame
*/
final class PhameBlogViewController extends PhameController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$blog = id(new PhameBlogQuery())
->setViewer($user)
->withIDs(array($this->id))
->executeOne();
if (!$blog) {
return new Aphront404Response();
}
$pager = id(new AphrontCursorPagerView())
->readFromRequest($request);
$posts = id(new PhamePostQuery())
->setViewer($user)
->withBlogPHIDs(array($blog->getPHID()))
->executeWithCursorPager($pager);
$nav = $this->renderSideNavFilterView(null);
$header = id(new PHUIHeaderView())
->setHeader($blog->getName())
->setUser($user)
->setPolicyObject($blog);
$handle_phids = array_merge(
mpull($posts, 'getBloggerPHID'),
mpull($posts, 'getBlogPHID'));
$this->loadHandles($handle_phids);
$actions = $this->renderActions($blog, $user);
$properties = $this->renderProperties($blog, $user, $actions);
$post_list = $this->renderPostList(
$posts,
$user,
pht('This blog has no visible posts.'));
require_celerity_resource('phame-css');
$post_list = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_LARGE)
->addClass('phame-post-list')
->appendChild($post_list);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($blog->getName(), $this->getApplicationURI());
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
$nav->appendChild(
array(
$crumbs,
$object_box,
$post_list,
));
return $this->buildApplicationPage(
$nav,
array(
'device' => true,
'title' => $blog->getName(),
));
}
private function renderProperties(
PhameBlog $blog,
PhabricatorUser $user,
PhabricatorActionListView $actions) {
require_celerity_resource('aphront-tooltip-css');
Javelin::initBehavior('phabricator-tooltips');
$properties = new PHUIPropertyListView();
$properties->setActionList($actions);
$properties->addProperty(
pht('Skin'),
$blog->getSkin());
$properties->addProperty(
pht('Domain'),
$blog->getDomain());
$feed_uri = PhabricatorEnv::getProductionURI(
$this->getApplicationURI('blog/feed/'.$blog->getID().'/'));
$properties->addProperty(
pht('Atom URI'),
javelin_tag('a',
array(
'href' => $feed_uri,
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => pht('Atom URI does not support custom domains.'),
'size' => 320,
)
),
$feed_uri));
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
$user,
$blog);
$properties->addProperty(
pht('Editable By'),
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
$properties->addProperty(
pht('Joinable By'),
$descriptions[PhabricatorPolicyCapability::CAN_JOIN]);
$engine = id(new PhabricatorMarkupEngine())
->setViewer($user)
->addObject($blog, PhameBlog::MARKUP_FIELD_DESCRIPTION)
->process();
$properties->addTextContent(
phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
$engine->getOutput($blog, PhameBlog::MARKUP_FIELD_DESCRIPTION)));
return $properties;
}
private function renderActions(PhameBlog $blog, PhabricatorUser $user) {
$actions = id(new PhabricatorActionListView())
->setObject($blog)
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($user);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$user,
$blog,
PhabricatorPolicyCapability::CAN_EDIT);
$can_join = PhabricatorPolicyFilter::hasCapability(
$user,
$blog,
PhabricatorPolicyCapability::CAN_JOIN);
- $must_use_form = $blog->getDomain();
-
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('new')
->setHref($this->getApplicationURI('post/edit/?blog='.$blog->getID()))
->setName(pht('Write Post'))
->setDisabled(!$can_join)
->setWorkflow(!$can_join));
$actions->addAction(
id(new PhabricatorActionView())
->setUser($user)
->setIcon('world')
- ->setHref($this->getApplicationURI('live/'.$blog->getID().'/'))
- ->setRenderAsForm($must_use_form)
+ ->setHref($blog->getLiveURI())
->setName(pht('View Live')));
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('edit')
->setHref($this->getApplicationURI('blog/edit/'.$blog->getID().'/'))
->setName('Edit Blog')
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('delete')
->setHref($this->getApplicationURI('blog/delete/'.$blog->getID().'/'))
->setName('Delete Blog')
->setDisabled(!$can_edit)
->setWorkflow(true));
return $actions;
}
}
diff --git a/src/applications/phame/controller/post/PhamePostViewController.php b/src/applications/phame/controller/post/PhamePostViewController.php
index bac0a370d3..000942d96a 100644
--- a/src/applications/phame/controller/post/PhamePostViewController.php
+++ b/src/applications/phame/controller/post/PhamePostViewController.php
@@ -1,209 +1,207 @@
<?php
/**
* @group phame
*/
final class PhamePostViewController extends PhameController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$post = id(new PhamePostQuery())
->setViewer($user)
->withIDs(array($this->id))
->executeOne();
if (!$post) {
return new Aphront404Response();
}
$nav = $this->renderSideNavFilterView();
$this->loadHandles(
array(
$post->getBlogPHID(),
$post->getBloggerPHID(),
));
$actions = $this->renderActions($post, $user);
$properties = $this->renderProperties($post, $user, $actions);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->setActionList($actions);
$crumbs->addTextCrumb(
$post->getTitle(),
$this->getApplicationURI('post/view/'.$post->getID().'/'));
$nav->appendChild($crumbs);
$header = id(new PHUIHeaderView())
->setHeader($post->getTitle())
->setUser($user)
->setPolicyObject($post);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
if ($post->isDraft()) {
$object_box->appendChild(
id(new AphrontErrorView())
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
->setTitle(pht('Draft Post'))
->appendChild(
pht('Only you can see this draft until you publish it. '.
'Use "Preview / Publish" to publish this post.')));
}
if (!$post->getBlog()) {
$object_box->appendChild(
id(new AphrontErrorView())
->setSeverity(AphrontErrorView::SEVERITY_WARNING)
->setTitle(pht('Not On A Blog'))
->appendChild(
pht('This post is not associated with a blog (the blog may have '.
'been deleted). Use "Move Post" to move it to a new blog.')));
}
$nav->appendChild(
array(
$object_box,
));
return $this->buildApplicationPage(
$nav,
array(
'title' => $post->getTitle(),
'device' => true,
));
}
private function renderActions(
PhamePost $post,
PhabricatorUser $user) {
$actions = id(new PhabricatorActionListView())
->setObject($post)
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($user);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$user,
$post,
PhabricatorPolicyCapability::CAN_EDIT);
$id = $post->getID();
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('edit')
->setHref($this->getApplicationURI('post/edit/'.$id.'/'))
->setName(pht('Edit Post'))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('move')
->setHref($this->getApplicationURI('post/move/'.$id.'/'))
->setName(pht('Move Post'))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
if ($post->isDraft()) {
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('preview')
->setHref($this->getApplicationURI('post/publish/'.$id.'/'))
->setName(pht('Preview / Publish')));
} else {
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('unpublish')
->setHref($this->getApplicationURI('post/unpublish/'.$id.'/'))
->setName(pht('Unpublish'))
->setWorkflow(true));
}
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('delete')
->setHref($this->getApplicationURI('post/delete/'.$id.'/'))
->setName(pht('Delete Post'))
->setDisabled(!$can_edit)
->setWorkflow(true));
$blog = $post->getBlog();
$can_view_live = $blog && !$post->isDraft();
- $must_use_form = $blog && $blog->getDomain();
if ($can_view_live) {
- $live_uri = 'live/'.$blog->getID().'/post/'.$post->getPhameTitle();
+ $live_uri = $blog->getLiveURI($post);
} else {
$live_uri = 'post/notlive/'.$post->getID().'/';
+ $live_uri = $this->getApplicationURI($live_uri);
}
- $live_uri = $this->getApplicationURI($live_uri);
$actions->addAction(
id(new PhabricatorActionView())
->setUser($user)
->setIcon('world')
->setHref($live_uri)
->setName(pht('View Live'))
- ->setRenderAsForm($must_use_form)
->setDisabled(!$can_view_live)
->setWorkflow(!$can_view_live));
return $actions;
}
private function renderProperties(
PhamePost $post,
PhabricatorUser $user,
PhabricatorActionListView $actions) {
$properties = id(new PHUIPropertyListView())
->setUser($user)
->setObject($post)
->setActionList($actions);
$properties->addProperty(
pht('Blog'),
$post->getBlogPHID()
? $this->getHandle($post->getBlogPHID())->renderLink()
: null);
$properties->addProperty(
pht('Blogger'),
$this->getHandle($post->getBloggerPHID())->renderLink());
$properties->addProperty(
pht('Published'),
$post->isDraft()
? pht('Draft')
: phabricator_datetime($post->getDatePublished(), $user));
$engine = id(new PhabricatorMarkupEngine())
->setViewer($user)
->addObject($post, PhamePost::MARKUP_FIELD_BODY)
->process();
$properties->invokeWillRenderEvent();
$properties->addTextContent(
phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
$engine->getOutput($post, PhamePost::MARKUP_FIELD_BODY)));
return $properties;
}
}
diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php
index 2a5ce6832c..39f3f14910 100644
--- a/src/applications/phame/storage/PhameBlog.php
+++ b/src/applications/phame/storage/PhameBlog.php
@@ -1,233 +1,248 @@
<?php
/**
* @group phame
*/
final class PhameBlog extends PhameDAO
implements PhabricatorPolicyInterface, PhabricatorMarkupInterface {
const MARKUP_FIELD_DESCRIPTION = 'markup:description';
const SKIN_DEFAULT = 'oblivious';
protected $name;
protected $description;
protected $domain;
protected $configData;
protected $creatorPHID;
protected $viewPolicy;
protected $editPolicy;
protected $joinPolicy;
private $bloggerPHIDs = self::ATTACHABLE;
private $bloggers = self::ATTACHABLE;
static private $requestBlog;
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'configData' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorPhamePHIDTypeBlog::TYPECONST);
}
public function getSkinRenderer(AphrontRequest $request) {
$spec = PhameSkinSpecification::loadOneSkinSpecification(
$this->getSkin());
if (!$spec) {
$spec = PhameSkinSpecification::loadOneSkinSpecification(
self::SKIN_DEFAULT);
}
if (!$spec) {
throw new Exception(
"This blog has an invalid skin, and the default skin failed to ".
"load.");
}
$skin = newv($spec->getSkinClass(), array($request));
$skin->setSpecification($spec);
return $skin;
}
/**
* Makes sure a given custom blog uri is properly configured in DNS
* to point at this Phabricator instance. If there is an error in
* the configuration, return a string describing the error and how
* to fix it. If there is no error, return an empty string.
*
* @return string
*/
public function validateCustomDomain($custom_domain) {
$example_domain = '(e.g. blog.example.com)';
$valid = '';
// note this "uri" should be pretty busted given the desired input
// so just use it to test if there's a protocol specified
$uri = new PhutilURI($custom_domain);
if ($uri->getProtocol()) {
return 'Do not specify a protocol, just the domain. '.$example_domain;
}
if (strpos($custom_domain, '/') !== false) {
return 'Do not specify a path, just the domain. '.$example_domain;
}
if (strpos($custom_domain, '.') === false) {
return 'Custom domain must contain at least one dot (.) because '.
'some browsers fail to set cookies on domains such as '.
'http://example. '.$example_domain;
}
return $valid;
}
public function getBloggerPHIDs() {
return $this->assertAttached($this->bloggerPHIDs);
}
public function attachBloggers(array $bloggers) {
assert_instances_of($bloggers, 'PhabricatorObjectHandle');
$this->bloggers = $bloggers;
return $this;
}
public function getBloggers() {
return $this->assertAttached($this->bloggers);
}
public function getSkin() {
$config = coalesce($this->getConfigData(), array());
return idx($config, 'skin', self::SKIN_DEFAULT);
}
public function setSkin($skin) {
$config = coalesce($this->getConfigData(), array());
$config['skin'] = $skin;
return $this->setConfigData($config);
}
static public function getSkinOptionsForSelect() {
$classes = id(new PhutilSymbolLoader())
->setAncestorClass('PhameBlogSkin')
->setType('class')
->setConcreteOnly(true)
->selectSymbolsWithoutLoading();
return ipull($classes, 'name', 'name');
}
public static function setRequestBlog(PhameBlog $blog) {
self::$requestBlog = $blog;
}
public static function getRequestBlog() {
return self::$requestBlog;
}
+ public function getLiveURI(PhamePost $post = null) {
+ if ($this->getDomain()) {
+ $base = new PhutilURI('http://'.$this->getDomain().'/');
+ } else {
+ $base = '/phame/live/'.$this->getID().'/';
+ $base = PhabricatorEnv::getURI($base);
+ }
+
+ if ($post) {
+ $base .= '/post/'.$post->getPhameTitle();
+ }
+
+ return $base;
+ }
+
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
PhabricatorPolicyCapability::CAN_JOIN,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
case PhabricatorPolicyCapability::CAN_JOIN:
return $this->getJoinPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
$can_edit = PhabricatorPolicyCapability::CAN_EDIT;
$can_join = PhabricatorPolicyCapability::CAN_JOIN;
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
// Users who can edit or post to a blog can always view it.
if (PhabricatorPolicyFilter::hasCapability($user, $this, $can_edit)) {
return true;
}
if (PhabricatorPolicyFilter::hasCapability($user, $this, $can_join)) {
return true;
}
break;
case PhabricatorPolicyCapability::CAN_JOIN:
// Users who can edit a blog can always post to it.
if (PhabricatorPolicyFilter::hasCapability($user, $this, $can_edit)) {
return true;
}
break;
}
return false;
}
public function describeAutomaticCapability($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return pht(
'Users who can edit or post on a blog can always view it.');
case PhabricatorPolicyCapability::CAN_JOIN:
return pht(
'Users who can edit a blog can always post on it.');
}
return null;
}
/* -( PhabricatorMarkupInterface Implementation )-------------------------- */
public function getMarkupFieldKey($field) {
$hash = PhabricatorHash::digest($this->getMarkupText($field));
return $this->getPHID().':'.$field.':'.$hash;
}
public function newMarkupEngine($field) {
return PhabricatorMarkupEngine::newPhameMarkupEngine();
}
public function getMarkupText($field) {
return $this->getDescription();
}
public function didMarkupText(
$field,
$output,
PhutilMarkupEngine $engine) {
return $output;
}
public function shouldUseMarkupCache($field) {
return (bool)$this->getPHID();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 24, 9:16 AM (21 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
182668
Default Alt Text
(22 KB)

Event Timeline