mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42:41 +01:00
Remove AphrontWriteGuard from phabricator/
Summary: See D3051. Test Plan: Loaded some pages. Reviewers: btrahan, vrana Reviewed By: vrana CC: aran Maniphest Tasks: T1283 Differential Revision: https://secure.phabricator.com/D3052
This commit is contained in:
parent
1e9120cdfb
commit
be63cb386b
3 changed files with 0 additions and 303 deletions
|
@ -98,7 +98,6 @@ phutil_register_library_map(array(
|
||||||
'AphrontRequestFailureView' => 'view/page/AphrontRequestFailureView.php',
|
'AphrontRequestFailureView' => 'view/page/AphrontRequestFailureView.php',
|
||||||
'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php',
|
'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php',
|
||||||
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
|
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
|
||||||
'AphrontScopedUnguardedWriteCapability' => 'aphront/writeguard/AphrontScopedUnguardedWriteCapability.php',
|
|
||||||
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
|
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
|
||||||
'AphrontSideNavView' => 'view/layout/AphrontSideNavView.php',
|
'AphrontSideNavView' => 'view/layout/AphrontSideNavView.php',
|
||||||
'AphrontTableView' => 'view/control/AphrontTableView.php',
|
'AphrontTableView' => 'view/control/AphrontTableView.php',
|
||||||
|
@ -108,7 +107,6 @@ phutil_register_library_map(array(
|
||||||
'AphrontUsageException' => 'aphront/exception/AphrontUsageException.php',
|
'AphrontUsageException' => 'aphront/exception/AphrontUsageException.php',
|
||||||
'AphrontView' => 'view/AphrontView.php',
|
'AphrontView' => 'view/AphrontView.php',
|
||||||
'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php',
|
'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php',
|
||||||
'AphrontWriteGuard' => 'aphront/writeguard/AphrontWriteGuard.php',
|
|
||||||
'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php',
|
'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php',
|
||||||
'CelerityResourceController' => 'infrastructure/celerity/CelerityResourceController.php',
|
'CelerityResourceController' => 'infrastructure/celerity/CelerityResourceController.php',
|
||||||
'CelerityResourceGraph' => 'infrastructure/celerity/CelerityResourceGraph.php',
|
'CelerityResourceGraph' => 'infrastructure/celerity/CelerityResourceGraph.php',
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2011 Facebook, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group aphront
|
|
||||||
*/
|
|
||||||
final class AphrontScopedUnguardedWriteCapability {
|
|
||||||
|
|
||||||
final public function __destruct() {
|
|
||||||
AphrontWriteGuard::endUnguardedWrites();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,273 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2012 Facebook, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Guard writes against CSRF. The Aphront structure takes care of most of this
|
|
||||||
* for you, you just need to call:
|
|
||||||
*
|
|
||||||
* AphrontWriteGuard::willWrite();
|
|
||||||
*
|
|
||||||
* ...before executing a write against any new kind of storage engine. MySQL
|
|
||||||
* databases and the default file storage engines are already covered, but if
|
|
||||||
* you introduce new types of datastores make sure their writes are guarded. If
|
|
||||||
* you don't guard writes and make a mistake doing CSRF checks in a controller,
|
|
||||||
* a CSRF vulnerability can escape undetected.
|
|
||||||
*
|
|
||||||
* If you need to execute writes on a page which doesn't have CSRF tokens (for
|
|
||||||
* example, because you need to do logging), you can temporarily disable the
|
|
||||||
* write guard by calling:
|
|
||||||
*
|
|
||||||
* AphrontWriteGuard::beginUnguardedWrites();
|
|
||||||
* do_logging_write();
|
|
||||||
* AphrontWriteGuard::endUnguardedWrites();
|
|
||||||
*
|
|
||||||
* This is dangerous, because it disables the backup layer of CSRF protection
|
|
||||||
* this class provides. You should need this only very, very rarely.
|
|
||||||
*
|
|
||||||
* @task protect Protecting Writes
|
|
||||||
* @task disable Disabling Protection
|
|
||||||
* @task manage Managing Write Guards
|
|
||||||
* @task internal Internals
|
|
||||||
*
|
|
||||||
* @group aphront
|
|
||||||
*/
|
|
||||||
final class AphrontWriteGuard {
|
|
||||||
|
|
||||||
private static $instance;
|
|
||||||
private static $allowUnguardedWrites = false;
|
|
||||||
|
|
||||||
private $callback;
|
|
||||||
private $allowDepth = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/* -( Managing Write Guards )---------------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new write guard for a request. Only one write guard may be
|
|
||||||
* active at a time. You must explicitly call @{method:dispose} when you are
|
|
||||||
* done with a write guard:
|
|
||||||
*
|
|
||||||
* $guard = new AphrontWriteGuard($callback);
|
|
||||||
* // ...
|
|
||||||
* $guard->dispose();
|
|
||||||
*
|
|
||||||
* Normally, you do not need to manage guards yourself -- the Aphront stack
|
|
||||||
* handles it for you.
|
|
||||||
*
|
|
||||||
* This class accepts a callback, which will be invoked when a write is
|
|
||||||
* attempted. The callback should validate the presence of a CSRF token in
|
|
||||||
* the request, or abort the request (e.g., by throwing an exception) if a
|
|
||||||
* valid token isn't present.
|
|
||||||
*
|
|
||||||
* @param callable CSRF callback.
|
|
||||||
* @return this
|
|
||||||
* @task manage
|
|
||||||
*/
|
|
||||||
public function __construct($callback) {
|
|
||||||
if (self::$instance) {
|
|
||||||
throw new Exception(
|
|
||||||
"An AphrontWriteGuard already exists. Dispose of the previous guard ".
|
|
||||||
"before creating a new one.");
|
|
||||||
}
|
|
||||||
if (self::$allowUnguardedWrites) {
|
|
||||||
throw new Exception(
|
|
||||||
"An AphrontWriteGuard is being created in a context which permits ".
|
|
||||||
"unguarded writes unconditionally. This is not allowed and indicates ".
|
|
||||||
"a serious error.");
|
|
||||||
}
|
|
||||||
$this->callback = $callback;
|
|
||||||
self::$instance = $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispose of the active write guard. You must call this method when you are
|
|
||||||
* done with a write guard. You do not normally need to call this yourself.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @task manage
|
|
||||||
*/
|
|
||||||
public function dispose() {
|
|
||||||
if ($this->allowDepth > 0) {
|
|
||||||
throw new Exception(
|
|
||||||
"Imbalanced AphrontWriteGuard: more beginUnguardedWrites() calls than ".
|
|
||||||
"endUnguardedWrites() calls.");
|
|
||||||
}
|
|
||||||
self::$instance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if there is an active write guard.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @task manage
|
|
||||||
*/
|
|
||||||
public static function isGuardActive() {
|
|
||||||
return (bool)self::$instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -( Protecting Writes )-------------------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Declare intention to perform a write, validating that writes are allowed.
|
|
||||||
* You should call this method before executing a write whenever you implement
|
|
||||||
* a new storage engine where information can be permanently kept.
|
|
||||||
*
|
|
||||||
* Writes are permitted if:
|
|
||||||
*
|
|
||||||
* - The request has valid CSRF tokens.
|
|
||||||
* - Unguarded writes have been temporarily enabled by a call to
|
|
||||||
* @{method:beginUnguardedWrites}.
|
|
||||||
* - All write guarding has been disabled with
|
|
||||||
* @{method:allowDangerousUnguardedWrites}.
|
|
||||||
*
|
|
||||||
* If none of these conditions are true, this method will throw and prevent
|
|
||||||
* the write.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @task protect
|
|
||||||
*/
|
|
||||||
public static function willWrite() {
|
|
||||||
if (!self::$instance) {
|
|
||||||
if (!self::$allowUnguardedWrites) {
|
|
||||||
throw new Exception(
|
|
||||||
"Unguarded write! There must be an active AphrontWriteGuard to ".
|
|
||||||
"perform writes.");
|
|
||||||
} else {
|
|
||||||
// Unguarded writes are being allowed unconditionally.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$instance = self::$instance;
|
|
||||||
if ($instance->allowDepth == 0) {
|
|
||||||
call_user_func($instance->callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -( Disabling Write Protection )----------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enter a scope which permits unguarded writes. This works like
|
|
||||||
* @{method:beginUnguardedWrites} but returns an object which will end
|
|
||||||
* the unguarded write scope when its __destruct() method is called. This
|
|
||||||
* is useful to more easily handle exceptions correctly in unguarded write
|
|
||||||
* blocks:
|
|
||||||
*
|
|
||||||
* // Restores the guard even if do_logging() throws.
|
|
||||||
* function unguarded_scope() {
|
|
||||||
* $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
|
||||||
* do_logging();
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @return AphrontScopedUnguardedWriteCapability Object which ends unguarded
|
|
||||||
* writes when it leaves scope.
|
|
||||||
* @task disable
|
|
||||||
*/
|
|
||||||
public static function beginScopedUnguardedWrites() {
|
|
||||||
self::beginUnguardedWrites();
|
|
||||||
return new AphrontScopedUnguardedWriteCapability();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begin a block which permits unguarded writes. You should use this very
|
|
||||||
* sparingly, and only for things like logging where CSRF is not a concern.
|
|
||||||
*
|
|
||||||
* You must pair every call to @{method:beginUnguardedWrites} with a call to
|
|
||||||
* @{method:endUnguardedWrites}:
|
|
||||||
*
|
|
||||||
* AphrontWriteGuard::beginUnguardedWrites();
|
|
||||||
* do_logging();
|
|
||||||
* AphrontWriteGuard::endUnguardedWrites();
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @task disable
|
|
||||||
*/
|
|
||||||
public static function beginUnguardedWrites() {
|
|
||||||
if (!self::$instance) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self::$instance->allowDepth++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Declare that you have finished performing unguarded writes. You must
|
|
||||||
* call this exactly once for each call to @{method:beginUnguardedWrites}.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @task disable
|
|
||||||
*/
|
|
||||||
public static function endUnguardedWrites() {
|
|
||||||
if (!self::$instance) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (self::$instance->allowDepth <= 0) {
|
|
||||||
throw new Exception(
|
|
||||||
"Imbalanced AphrontWriteGuard: more endUnguardedWrites() calls than ".
|
|
||||||
"beginUnguardedWrites() calls.");
|
|
||||||
}
|
|
||||||
self::$instance->allowDepth--;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow execution of unguarded writes. This is ONLY appropriate for use in
|
|
||||||
* script contexts or other contexts where you are guaranteed to never be
|
|
||||||
* vulnerable to CSRF concerns. Calling this method is EXTREMELY DANGEROUS
|
|
||||||
* if you do not understand the consequences.
|
|
||||||
*
|
|
||||||
* If you need to perform unguarded writes on an otherwise guarded workflow
|
|
||||||
* which is vulnerable to CSRF, use @{method:beginUnguardedWrites}.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @task disable
|
|
||||||
*/
|
|
||||||
public static function allowDangerousUnguardedWrites($allow) {
|
|
||||||
if (self::$instance) {
|
|
||||||
throw new Exception(
|
|
||||||
"You can not unconditionally disable AphrontWriteGuard by calling ".
|
|
||||||
"allowDangerousUnguardedWrites() while a write guard is active. Use ".
|
|
||||||
"beginUnguardedWrites() to temporarily allow unguarded writes.");
|
|
||||||
}
|
|
||||||
self::$allowUnguardedWrites = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -( Internals )---------------------------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the object is destroyed, make sure @{method:dispose} was called.
|
|
||||||
*
|
|
||||||
* @task internal
|
|
||||||
*/
|
|
||||||
public function __destruct() {
|
|
||||||
if (isset(self::$instance)) {
|
|
||||||
throw new Exception(
|
|
||||||
"AphrontWriteGuard was not properly disposed of! Call dispose() on ".
|
|
||||||
"every AphrontWriteGuard object you instantiate.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue