Page MenuHomestyx hydra

No OneTemporary

diff --git a/.gitignore b/.gitignore
index a969224fa6..07a2f0da43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.DS_Store
._*
/docs/
/src/.phutil_module_cache
+/conf/custom/*
diff --git a/conf/default.conf.php b/conf/default.conf.php
new file mode 100644
index 0000000000..a5bb05d2fa
--- /dev/null
+++ b/conf/default.conf.php
@@ -0,0 +1,46 @@
+<?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.
+ */
+
+return array(
+
+ // The root URI which Phabricator is installed on.
+ // Example: "http://phabricator.example.com/"
+ 'phabricator.base-uri' => null,
+
+
+ //
+ 'phabricator.csrf-key' => '0b7ec0592e0a2829d8b71df2fa269b2c6172eca3',
+
+
+// -- Facebook ---------------------------------------------------------------
+
+ // Can users use Facebook credentials to login to Phabricator?
+ 'facebook.auth-enabled' => false,
+
+ // The Facebook "Application ID" to use for Facebook API access.
+ 'facebook.application-id' => null,
+
+ // The Facebook "Application Secret" to use for Facebook API access.
+ 'facebook.application-secret' => null,
+
+ 'recaptcha.public-key' => null,
+ 'recaptcha.private-key' => null,
+
+
+
+);
diff --git a/src/infratructure/javelin/api/Javelin.php b/conf/development.conf.php
similarity index 74%
copy from src/infratructure/javelin/api/Javelin.php
copy to conf/development.conf.php
index b6e2a3d9cf..85673eab81 100644
--- a/src/infratructure/javelin/api/Javelin.php
+++ b/conf/development.conf.php
@@ -1,24 +1,22 @@
<?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.
*/
-final class Javelin {
- public static function initBehavior($behavior, array $config = array()) {
- $response = CelerityAPI::getStaticResourceResponse();
- $response->initBehavior($behavior, $config);
- }
-}
+return array(
+
+
+) + phabricator_read_config_file('default');
diff --git a/src/infratructure/javelin/api/Javelin.php b/conf/production.conf.php
similarity index 74%
copy from src/infratructure/javelin/api/Javelin.php
copy to conf/production.conf.php
index b6e2a3d9cf..9af5c29c9a 100644
--- a/src/infratructure/javelin/api/Javelin.php
+++ b/conf/production.conf.php
@@ -1,24 +1,23 @@
<?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.
*/
-final class Javelin {
- public static function initBehavior($behavior, array $config = array()) {
- $response = CelerityAPI::getStaticResourceResponse();
- $response->initBehavior($behavior, $config);
- }
-}
+return array(
+
+
+) + phabricator_read_config_file('default');
+
diff --git a/externals/recaptcha/LICENSE b/externals/recaptcha/LICENSE
new file mode 100644
index 0000000000..b612f71f01
--- /dev/null
+++ b/externals/recaptcha/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
+AUTHORS:
+ Mike Crawford
+ Ben Maurer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/externals/recaptcha/recaptchalib.php b/externals/recaptcha/recaptchalib.php
new file mode 100644
index 0000000000..32c4f4d758
--- /dev/null
+++ b/externals/recaptcha/recaptchalib.php
@@ -0,0 +1,277 @@
+<?php
+/*
+ * This is a PHP library that handles calling reCAPTCHA.
+ * - Documentation and latest version
+ * http://recaptcha.net/plugins/php/
+ * - Get a reCAPTCHA API Key
+ * https://www.google.com/recaptcha/admin/create
+ * - Discussion group
+ * http://groups.google.com/group/recaptcha
+ *
+ * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
+ * AUTHORS:
+ * Mike Crawford
+ * Ben Maurer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * The reCAPTCHA server URL's
+ */
+define("RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api");
+define("RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api");
+define("RECAPTCHA_VERIFY_SERVER", "www.google.com");
+
+/**
+ * Encodes the given data into a query string format
+ * @param $data - array of string elements to be encoded
+ * @return string - encoded request
+ */
+function _recaptcha_qsencode ($data) {
+ $req = "";
+ foreach ( $data as $key => $value )
+ $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
+
+ // Cut the last '&'
+ $req=substr($req,0,strlen($req)-1);
+ return $req;
+}
+
+
+
+/**
+ * Submits an HTTP POST to a reCAPTCHA server
+ * @param string $host
+ * @param string $path
+ * @param array $data
+ * @param int port
+ * @return array response
+ */
+function _recaptcha_http_post($host, $path, $data, $port = 80) {
+
+ $req = _recaptcha_qsencode ($data);
+
+ $http_request = "POST $path HTTP/1.0\r\n";
+ $http_request .= "Host: $host\r\n";
+ $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
+ $http_request .= "Content-Length: " . strlen($req) . "\r\n";
+ $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
+ $http_request .= "\r\n";
+ $http_request .= $req;
+
+ $response = '';
+ if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
+ die ('Could not open socket');
+ }
+
+ fwrite($fs, $http_request);
+
+ while ( !feof($fs) )
+ $response .= fgets($fs, 1160); // One TCP-IP packet
+ fclose($fs);
+ $response = explode("\r\n\r\n", $response, 2);
+
+ return $response;
+}
+
+
+
+/**
+ * Gets the challenge HTML (javascript and non-javascript version).
+ * This is called from the browser, and the resulting reCAPTCHA HTML widget
+ * is embedded within the HTML form it was called from.
+ * @param string $pubkey A public key for reCAPTCHA
+ * @param string $error The error given by reCAPTCHA (optional, default is null)
+ * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
+
+ * @return string - The HTML to be embedded in the user's form.
+ */
+function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
+{
+ if ($pubkey == null || $pubkey == '') {
+ die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
+ }
+
+ if ($use_ssl) {
+ $server = RECAPTCHA_API_SECURE_SERVER;
+ } else {
+ $server = RECAPTCHA_API_SERVER;
+ }
+
+ $errorpart = "";
+ if ($error) {
+ $errorpart = "&amp;error=" . $error;
+ }
+ return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
+
+ <noscript>
+ <iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
+ <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
+ <input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
+ </noscript>';
+}
+
+
+
+
+/**
+ * A ReCaptchaResponse is returned from recaptcha_check_answer()
+ */
+class ReCaptchaResponse {
+ var $is_valid;
+ var $error;
+}
+
+
+/**
+ * Calls an HTTP POST function to verify if the user's guess was correct
+ * @param string $privkey
+ * @param string $remoteip
+ * @param string $challenge
+ * @param string $response
+ * @param array $extra_params an array of extra variables to post to the server
+ * @return ReCaptchaResponse
+ */
+function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
+{
+ if ($privkey == null || $privkey == '') {
+ die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
+ }
+
+ if ($remoteip == null || $remoteip == '') {
+ die ("For security reasons, you must pass the remote ip to reCAPTCHA");
+ }
+
+
+
+ //discard spam submissions
+ if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
+ $recaptcha_response = new ReCaptchaResponse();
+ $recaptcha_response->is_valid = false;
+ $recaptcha_response->error = 'incorrect-captcha-sol';
+ return $recaptcha_response;
+ }
+
+ $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
+ array (
+ 'privatekey' => $privkey,
+ 'remoteip' => $remoteip,
+ 'challenge' => $challenge,
+ 'response' => $response
+ ) + $extra_params
+ );
+
+ $answers = explode ("\n", $response [1]);
+ $recaptcha_response = new ReCaptchaResponse();
+
+ if (trim ($answers [0]) == 'true') {
+ $recaptcha_response->is_valid = true;
+ }
+ else {
+ $recaptcha_response->is_valid = false;
+ $recaptcha_response->error = $answers [1];
+ }
+ return $recaptcha_response;
+
+}
+
+/**
+ * gets a URL where the user can sign up for reCAPTCHA. If your application
+ * has a configuration page where you enter a key, you should provide a link
+ * using this function.
+ * @param string $domain The domain where the page is hosted
+ * @param string $appname The name of your application
+ */
+function recaptcha_get_signup_url ($domain = null, $appname = null) {
+ return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
+}
+
+function _recaptcha_aes_pad($val) {
+ $block_size = 16;
+ $numpad = $block_size - (strlen ($val) % $block_size);
+ return str_pad($val, strlen ($val) + $numpad, chr($numpad));
+}
+
+/* Mailhide related code */
+
+function _recaptcha_aes_encrypt($val,$ky) {
+ if (! function_exists ("mcrypt_encrypt")) {
+ die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
+ }
+ $mode=MCRYPT_MODE_CBC;
+ $enc=MCRYPT_RIJNDAEL_128;
+ $val=_recaptcha_aes_pad($val);
+ return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
+}
+
+
+function _recaptcha_mailhide_urlbase64 ($x) {
+ return strtr(base64_encode ($x), '+/', '-_');
+}
+
+/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
+function recaptcha_mailhide_url($pubkey, $privkey, $email) {
+ if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
+ die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
+ "you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
+ }
+
+
+ $ky = pack('H*', $privkey);
+ $cryptmail = _recaptcha_aes_encrypt ($email, $ky);
+
+ return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
+}
+
+/**
+ * gets the parts of the email to expose to the user.
+ * eg, given johndoe@example,com return ["john", "example.com"].
+ * the email is then displayed as john...@example.com
+ */
+function _recaptcha_mailhide_email_parts ($email) {
+ $arr = preg_split("/@/", $email );
+
+ if (strlen ($arr[0]) <= 4) {
+ $arr[0] = substr ($arr[0], 0, 1);
+ } else if (strlen ($arr[0]) <= 6) {
+ $arr[0] = substr ($arr[0], 0, 3);
+ } else {
+ $arr[0] = substr ($arr[0], 0, 4);
+ }
+ return $arr;
+}
+
+/**
+ * Gets html to display an email address given a public an private key.
+ * to get a key, go to:
+ *
+ * http://www.google.com/recaptcha/mailhide/apikey
+ */
+function recaptcha_mailhide_html($pubkey, $privkey, $email) {
+ $emailparts = _recaptcha_mailhide_email_parts ($email);
+ $url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
+
+ return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
+ "' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
+
+}
+
+
+?>
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 7f24c77fc2..261d63ec43 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,331 +1,342 @@
<?php
/**
* This file is automatically generated. Use 'phutil_mapper.php' to rebuild it.
* @generated
*/
phutil_register_library_map(array(
'class' =>
array(
'Aphront400Response' => 'aphront/response/400',
'Aphront404Response' => 'aphront/response/404',
'AphrontAjaxResponse' => 'aphront/response/ajax',
'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
'AphrontController' => 'aphront/controller',
'AphrontDatabaseConnection' => 'storage/connection/base',
'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration',
'AphrontDefaultApplicationController' => 'aphront/default/controller',
'AphrontDialogResponse' => 'aphront/response/dialog',
'AphrontDialogView' => 'view/dialog',
'AphrontErrorView' => 'view/form/error',
'AphrontException' => 'aphront/exception/base',
'AphrontFileResponse' => 'aphront/response/file',
'AphrontFormCheckboxControl' => 'view/form/control/checkbox',
'AphrontFormControl' => 'view/form/control/base',
'AphrontFormFileControl' => 'view/form/control/file',
'AphrontFormMarkupControl' => 'view/form/control/markup',
+ 'AphrontFormPasswordControl' => 'view/form/control/password',
+ 'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha',
'AphrontFormSelectControl' => 'view/form/control/select',
'AphrontFormStaticControl' => 'view/form/control/static',
'AphrontFormSubmitControl' => 'view/form/control/submit',
'AphrontFormTextAreaControl' => 'view/form/control/textarea',
'AphrontFormTextControl' => 'view/form/control/text',
'AphrontFormTokenizerControl' => 'view/form/control/tokenizer',
'AphrontFormView' => 'view/form/base',
'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql',
'AphrontNullView' => 'view/null',
'AphrontPageView' => 'view/page/base',
'AphrontPanelView' => 'view/layout/panel',
'AphrontQueryConnectionException' => 'storage/exception/connection',
'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost',
'AphrontQueryCountException' => 'storage/exception/count',
'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey',
'AphrontQueryException' => 'storage/exception/base',
'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing',
'AphrontQueryParameterException' => 'storage/exception/parameter',
'AphrontQueryRecoverableException' => 'storage/exception/recoverable',
'AphrontRedirectException' => 'aphront/exception/redirect',
'AphrontRedirectResponse' => 'aphront/response/redirect',
'AphrontRequest' => 'aphront/request',
'AphrontRequestFailureView' => 'view/page/failure',
'AphrontResponse' => 'aphront/response/base',
'AphrontSideNavView' => 'view/layout/sidenav',
'AphrontTableView' => 'view/control/table',
'AphrontURIMapper' => 'aphront/mapper',
'AphrontView' => 'view/base',
'AphrontWebpageResponse' => 'aphront/response/webpage',
- 'CelerityAPI' => 'infratructure/celerity/api',
- 'CelerityResourceController' => 'infratructure/celerity/controller',
- 'CelerityResourceMap' => 'infratructure/celerity/map',
- 'CelerityStaticResourceResponse' => 'infratructure/celerity/response',
+ 'CelerityAPI' => 'infrastructure/celerity/api',
+ 'CelerityResourceController' => 'infrastructure/celerity/controller',
+ 'CelerityResourceMap' => 'infrastructure/celerity/map',
+ 'CelerityStaticResourceResponse' => 'infrastructure/celerity/response',
'ConduitAPIMethod' => 'applications/conduit/method/base',
'ConduitAPIRequest' => 'applications/conduit/protocol/request',
'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect',
'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff',
'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty',
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
'ConduitException' => 'applications/conduit/protocol/exception',
'DifferentialAction' => 'applications/differential/constants/action',
'DifferentialAddCommentView' => 'applications/differential/view/addcomment',
'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome',
'DifferentialChangeType' => 'applications/differential/constants/changetype',
'DifferentialChangeset' => 'applications/differential/storage/changeset',
'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview',
'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview',
'DifferentialChangesetParser' => 'applications/differential/parser/changeset',
'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview',
'DifferentialComment' => 'applications/differential/storage/comment',
'DifferentialCommentEditor' => 'applications/differential/editor/comment',
'DifferentialCommentMail' => 'applications/differential/mail/comment',
'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave',
'DifferentialController' => 'applications/differential/controller/base',
'DifferentialDAO' => 'applications/differential/storage/base',
'DifferentialDiff' => 'applications/differential/storage/diff',
'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent',
'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty',
'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents',
'DifferentialDiffViewController' => 'applications/differential/controller/diffview',
'DifferentialHunk' => 'applications/differential/storage/hunk',
'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
'DifferentialMail' => 'applications/differential/mail/base',
'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup',
'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff',
'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
'DifferentialRevision' => 'applications/differential/storage/revision',
'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist',
'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment',
'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem',
'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail',
'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit',
'DifferentialRevisionEditor' => 'applications/differential/editor/revision',
'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus',
'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
- 'Javelin' => 'infratructure/javelin/api',
+ 'Javelin' => 'infrastructure/javelin/api',
'LiskDAO' => 'storage/lisk/dao',
'Phabricator404Controller' => 'applications/base/controller/404',
'PhabricatorAuthController' => 'applications/auth/controller/base',
'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog',
'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console',
'PhabricatorConduitController' => 'applications/conduit/controller/base',
'PhabricatorConduitDAO' => 'applications/conduit/storage/base',
'PhabricatorConduitLogController' => 'applications/conduit/controller/log',
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog',
'PhabricatorController' => 'applications/base/controller/base',
'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist',
'PhabricatorDirectoryController' => 'applications/directory/controller/base',
'PhabricatorDirectoryDAO' => 'applications/directory/storage/base',
'PhabricatorDirectoryItem' => 'applications/directory/storage/item',
'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete',
'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit',
'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist',
'PhabricatorDirectoryMainController' => 'applications/directory/controller/main',
- 'PhabricatorFacebookConnectController' => 'applications/auth/controller/facebookconnect',
+ 'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
+ 'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
+ 'PhabricatorEnv' => 'infrastructure/env',
+ 'PhabricatorFacebookAuthController' => 'applications/auth/controller/facebookauth',
+ 'PhabricatorFacebookAuthDiagnosticsController' => 'applications/auth/controller/facebookauth/diagnostics',
'PhabricatorFile' => 'applications/files/storage/file',
'PhabricatorFileController' => 'applications/files/controller/base',
'PhabricatorFileDAO' => 'applications/files/storage/base',
'PhabricatorFileListController' => 'applications/files/controller/list',
'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob',
'PhabricatorFileURI' => 'applications/files/uri',
'PhabricatorFileUploadController' => 'applications/files/controller/upload',
'PhabricatorFileViewController' => 'applications/files/controller/view',
'PhabricatorLiskDAO' => 'applications/base/storage/lisk',
'PhabricatorLoginController' => 'applications/auth/controller/login',
'PhabricatorLogoutController' => 'applications/auth/controller/logout',
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite',
'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base',
'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list',
'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail',
'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist',
'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit',
'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists',
'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send',
'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view',
'PhabricatorObjectHandle' => 'applications/phid/handle',
'PhabricatorObjectHandleData' => 'applications/phid/handle/data',
'PhabricatorPHID' => 'applications/phid/storage/phid',
'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate',
'PhabricatorPHIDController' => 'applications/phid/controller/base',
'PhabricatorPHIDDAO' => 'applications/phid/storage/base',
'PhabricatorPHIDListController' => 'applications/phid/controller/list',
'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup',
'PhabricatorPHIDType' => 'applications/phid/storage/type',
'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit',
'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist',
'PhabricatorPeopleController' => 'applications/people/controller/base',
'PhabricatorPeopleEditController' => 'applications/people/controller/edit',
'PhabricatorPeopleListController' => 'applications/people/controller/list',
'PhabricatorPeopleProfileController' => 'applications/people/controller/profile',
'PhabricatorStandardPageView' => 'view/page/standard',
'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base',
'PhabricatorUser' => 'applications/people/storage/user',
'PhabricatorUserDAO' => 'applications/people/storage/base',
),
'function' =>
array(
'_qsprintf_check_scalar_type' => 'storage/qsprintf',
'_qsprintf_check_type' => 'storage/qsprintf',
- 'celerity_generate_unique_node_id' => 'infratructure/celerity/api',
- 'celerity_register_resource_map' => 'infratructure/celerity/map',
- 'javelin_render_tag' => 'infratructure/javelin/markup',
+ 'celerity_generate_unique_node_id' => 'infrastructure/celerity/api',
+ 'celerity_register_resource_map' => 'infrastructure/celerity/map',
+ 'javelin_render_tag' => 'infrastructure/javelin/markup',
'phabricator_format_relative_time' => 'view/utils',
'phabricator_format_timestamp' => 'view/utils',
'phabricator_format_units_generic' => 'view/utils',
'qsprintf' => 'storage/qsprintf',
'queryfx' => 'storage/queryfx',
'queryfx_all' => 'storage/queryfx',
'queryfx_one' => 'storage/queryfx',
- 'require_celerity_resource' => 'infratructure/celerity/api',
+ 'require_celerity_resource' => 'infrastructure/celerity/api',
'vqsprintf' => 'storage/qsprintf',
'vqueryfx' => 'storage/queryfx',
'vqueryfx_all' => 'storage/queryfx',
'xsprintf_query' => 'storage/qsprintf',
),
'requires_class' =>
array(
'Aphront400Response' => 'AphrontResponse',
'Aphront404Response' => 'AphrontResponse',
'AphrontAjaxResponse' => 'AphrontResponse',
'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
'AphrontDefaultApplicationController' => 'AphrontController',
'AphrontDialogResponse' => 'AphrontResponse',
'AphrontDialogView' => 'AphrontView',
'AphrontErrorView' => 'AphrontView',
'AphrontFileResponse' => 'AphrontResponse',
'AphrontFormCheckboxControl' => 'AphrontFormControl',
'AphrontFormControl' => 'AphrontView',
'AphrontFormFileControl' => 'AphrontFormControl',
'AphrontFormMarkupControl' => 'AphrontFormControl',
+ 'AphrontFormPasswordControl' => 'AphrontFormControl',
+ 'AphrontFormRecaptchaControl' => 'AphrontFormControl',
'AphrontFormSelectControl' => 'AphrontFormControl',
'AphrontFormStaticControl' => 'AphrontFormControl',
'AphrontFormSubmitControl' => 'AphrontFormControl',
'AphrontFormTextAreaControl' => 'AphrontFormControl',
'AphrontFormTextControl' => 'AphrontFormControl',
'AphrontFormTokenizerControl' => 'AphrontFormControl',
'AphrontFormView' => 'AphrontView',
'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection',
'AphrontNullView' => 'AphrontView',
'AphrontPageView' => 'AphrontView',
'AphrontPanelView' => 'AphrontView',
'AphrontQueryConnectionException' => 'AphrontQueryException',
'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException',
'AphrontQueryCountException' => 'AphrontQueryException',
'AphrontQueryDuplicateKeyException' => 'AphrontQueryException',
'AphrontQueryObjectMissingException' => 'AphrontQueryException',
'AphrontQueryParameterException' => 'AphrontQueryException',
'AphrontQueryRecoverableException' => 'AphrontQueryException',
'AphrontRedirectException' => 'AphrontException',
'AphrontRedirectResponse' => 'AphrontResponse',
'AphrontRequestFailureView' => 'AphrontView',
'AphrontSideNavView' => 'AphrontView',
'AphrontTableView' => 'AphrontView',
'AphrontWebpageResponse' => 'AphrontResponse',
'CelerityResourceController' => 'AphrontController',
'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod',
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
'DifferentialAddCommentView' => 'AphrontView',
'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail',
'DifferentialChangeset' => 'DifferentialDAO',
'DifferentialChangesetDetailView' => 'AphrontView',
'DifferentialChangesetListView' => 'AphrontView',
'DifferentialChangesetViewController' => 'DifferentialController',
'DifferentialComment' => 'DifferentialDAO',
'DifferentialCommentMail' => 'DifferentialMail',
'DifferentialCommentSaveController' => 'DifferentialController',
'DifferentialController' => 'PhabricatorController',
'DifferentialDAO' => 'PhabricatorLiskDAO',
'DifferentialDiff' => 'DifferentialDAO',
'DifferentialDiffContentMail' => 'DifferentialMail',
'DifferentialDiffProperty' => 'DifferentialDAO',
'DifferentialDiffTableOfContentsView' => 'AphrontView',
'DifferentialDiffViewController' => 'DifferentialController',
'DifferentialHunk' => 'DifferentialDAO',
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
'DifferentialReviewRequestMail' => 'DifferentialMail',
'DifferentialRevision' => 'DifferentialDAO',
'DifferentialRevisionCommentListView' => 'AphrontView',
'DifferentialRevisionCommentView' => 'AphrontView',
'DifferentialRevisionDetailView' => 'AphrontView',
'DifferentialRevisionEditController' => 'DifferentialController',
'DifferentialRevisionListController' => 'DifferentialController',
'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
'DifferentialRevisionViewController' => 'DifferentialController',
'Phabricator404Controller' => 'PhabricatorController',
'PhabricatorAuthController' => 'PhabricatorController',
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
'PhabricatorConduitController' => 'PhabricatorController',
'PhabricatorConduitDAO' => 'PhabricatorLiskDAO',
'PhabricatorConduitLogController' => 'PhabricatorConduitController',
'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
'PhabricatorController' => 'AphrontController',
'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryController' => 'PhabricatorController',
'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO',
'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO',
'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController',
- 'PhabricatorFacebookConnectController' => 'PhabricatorAuthController',
+ 'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
+ 'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
+ 'PhabricatorFacebookAuthController' => 'PhabricatorAuthController',
+ 'PhabricatorFacebookAuthDiagnosticsController' => 'PhabricatorAuthController',
'PhabricatorFile' => 'PhabricatorFileDAO',
'PhabricatorFileController' => 'PhabricatorController',
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
'PhabricatorFileListController' => 'PhabricatorFileController',
'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
'PhabricatorFileUploadController' => 'PhabricatorFileController',
'PhabricatorFileViewController' => 'PhabricatorFileController',
'PhabricatorLiskDAO' => 'LiskDAO',
'PhabricatorLoginController' => 'PhabricatorAuthController',
'PhabricatorLogoutController' => 'PhabricatorAuthController',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMetaMTAController' => 'PhabricatorController',
'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController',
'PhabricatorPHID' => 'PhabricatorPHIDDAO',
'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController',
'PhabricatorPHIDController' => 'PhabricatorController',
'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO',
'PhabricatorPHIDListController' => 'PhabricatorPHIDController',
'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController',
'PhabricatorPHIDType' => 'PhabricatorPHIDDAO',
'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController',
'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController',
'PhabricatorPeopleController' => 'PhabricatorController',
'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
'PhabricatorStandardPageView' => 'AphrontPageView',
'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
'PhabricatorUser' => 'PhabricatorUserDAO',
'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
),
'requires_interface' =>
array(
),
));
diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
index ef0619b0cc..a7dbbe58cf 100644
--- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
+++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
@@ -1,188 +1,195 @@
<?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
*/
class AphrontDefaultApplicationConfiguration
extends AphrontApplicationConfiguration {
public function getApplicationName() {
return 'aphront-default';
}
public function getURIMap() {
return array(
'/repository/' => array(
'$' => 'RepositoryListController',
'new/$' => 'RepositoryEditController',
'edit/(?<id>\d+)/$' => 'RepositoryEditController',
'delete/(?<id>\d+)/$' => 'RepositoryDeleteController',
),
'/' => array(
'$' => 'PhabricatorDirectoryMainController',
),
'/directory/' => array(
'item/$'
=> 'PhabricatorDirectoryItemListController',
'item/edit/(?:(?<id>\d+)/)?$'
=> 'PhabricatorDirectoryItemEditController',
'item/delete/(?<id>\d+)/'
=> 'PhabricatorDirectoryItemDeleteController',
'category/$'
=> 'PhabricatorDirectoryCategoryListController',
'category/edit/(?:(?<id>\d+)/)?$'
=> 'PhabricatorDirectoryCategoryEditController',
'category/delete/(?<id>\d+)/'
=> 'PhabricatorDirectoryCategoryDeleteController',
),
'/file/' => array(
'$' => 'PhabricatorFileListController',
'upload/$' => 'PhabricatorFileUploadController',
'(?<view>info)/(?<phid>[^/]+)/' => 'PhabricatorFileViewController',
'(?<view>view)/(?<phid>[^/]+)/' => 'PhabricatorFileViewController',
'(?<view>download)/(?<phid>[^/]+)/' => 'PhabricatorFileViewController',
),
'/phid/' => array(
'$' => 'PhabricatorPHIDLookupController',
'list/$' => 'PhabricatorPHIDListController',
'type/$' => 'PhabricatorPHIDTypeListController',
'type/edit/(?:(?<id>\d+)/)?$' => 'PhabricatorPHIDTypeEditController',
'new/$' => 'PhabricatorPHIDAllocateController',
),
'/people/' => array(
'$' => 'PhabricatorPeopleListController',
'edit/(?:(?<username>\w+)/)?$' => 'PhabricatorPeopleEditController',
),
'/p/(?<username>\w+)/$' => 'PhabricatorPeopleProfileController',
'/conduit/' => array(
'$' => 'PhabricatorConduitConsoleController',
'method/(?<method>[^/]+)$' => 'PhabricatorConduitConsoleController',
'log/$' => 'PhabricatorConduitLogController',
),
'/api/(?<method>[^/]+)$' => 'PhabricatorConduitAPIController',
'/D(?<id>\d+)' => 'DifferentialRevisionViewController',
'/differential/' => array(
'$' => 'DifferentialRevisionListController',
'filter/(?<filter>\w+)/$' => 'DifferentialRevisionListController',
'diff/(?<id>\d+)/$' => 'DifferentialDiffViewController',
'changeset/(?<id>\d+)/$' => 'DifferentialChangesetViewController',
'revision/edit/(?:(?<id>\d+)/)?$'
=> 'DifferentialRevisionEditController',
'comment/' => array(
'preview/$' => 'DifferentialCommentPreviewController',
'save/$' => 'DifferentialCommentSaveController',
'inline/' => array(
'preview/$' => 'DifferentialInlineCommentPreviewController',
'edit/$' => 'DifferentialInlineCommentEditController',
),
),
),
'/res/' => array(
'(?<package>pkg/)?(?<hash>[a-f0-9]{8})/(?<path>.+\.(?:css|js))$'
=> 'CelerityResourceController',
),
'/typeahead/' => array(
'common/(?<type>\w+)/$'
=> 'PhabricatorTypeaheadCommonDatasourceController',
),
'/mail/' => array(
'$' => 'PhabricatorMetaMTAListController',
'send/$' => 'PhabricatorMetaMTASendController',
'view/(?<id>\d+)/$' => 'PhabricatorMetaMTAViewController',
'lists/$' => 'PhabricatorMetaMTAMailingListsController',
'lists/edit/(?:(?<id>\d+)/)?$'
=> 'PhabricatorMetaMTAMailingListEditController',
),
- '/login/$' => 'PhabricatorLoginController',
+ '/login/' => array(
+ '$' => 'PhabricatorLoginController',
+ 'email/$' => 'PhabricatorEmailLoginController',
+ 'etoken/(?<token>\w+)/$' => 'PhabricatorEmailTokenController',
+ ),
'/logout/$' => 'PhabricatorLogoutController',
- '/facebook-connect/$' => 'PhabricatorFacebookConnectController',
+ '/facebook-auth/' => array(
+ '$' => 'PhabricatorFacebookAuthController',
+ 'diagnose/$' => 'PhabricatorFacebookAuthDiagnosticsController',
+ ),
);
}
public function buildRequest() {
$request = new AphrontRequest($this->getHost(), $this->getPath());
$request->setRequestData($_GET + $_POST);
return $request;
}
public function handleException(Exception $ex) {
$class = phutil_escape_html(get_class($ex));
$message = phutil_escape_html($ex->getMessage());
$content =
'<div class="aphront-unhandled-exception">'.
'<h1>Unhandled Exception "'.$class.'": '.$message.'</h1>'.
'<code>'.phutil_escape_html((string)$ex).'</code>'.
'</div>';
$view = new PhabricatorStandardPageView();
$view->appendChild($content);
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
return $response;
}
public function willSendResponse(AphrontResponse $response) {
$request = $this->getRequest();
if ($response instanceof AphrontDialogResponse) {
if (!$request->isAjax()) {
$view = new PhabricatorStandardPageView();
$view->appendChild(
'<div style="padding: 2em 0;">'.
$response->buildResponseString().
'</div>');
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
return $response;
}
} else if ($response instanceof Aphront404Response) {
$failure = new AphrontRequestFailureView();
$failure->setHeader('404 Not Found');
$failure->appendChild(
'<p>The page you requested was not found.</p>');
$view = new PhabricatorStandardPageView();
$view->setTitle('404 Not Found');
$view->appendChild($failure);
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
$response->setHTTPResponseCode(404);
return $response;
}
return $response;
}
public function build404Controller() {
return array(new Phabricator404Controller($this->getRequest()), array());
}
}
diff --git a/src/aphront/request/AphrontRequest.php b/src/aphront/request/AphrontRequest.php
index 6cc50fa2f5..a231ff30e2 100644
--- a/src/aphront/request/AphrontRequest.php
+++ b/src/aphront/request/AphrontRequest.php
@@ -1,127 +1,135 @@
<?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
*/
class AphrontRequest {
const TYPE_AJAX = '__ajax__';
const TYPE_FORM = '__form__';
private $host;
private $path;
private $requestData;
private $user;
+ private $env;
+
+ final public function setEnvConfig(array $conf) {
+ $this->env = $conf;
+ return $this;
+ }
+
+ final public function getEnvConfig($key, $default = null) {
+ return idx($this->env, $key, $default);
+ }
final public function __construct($host, $path) {
$this->host = $host;
$this->path = $path;
}
final public function setRequestData(array $request_data) {
$this->requestData = $request_data;
return $this;
}
final public function getPath() {
return $this->path;
}
final public function getHost() {
return $this->host;
}
final public function getInt($name, $default = null) {
if (isset($this->requestData[$name])) {
return (int)$this->requestData[$name];
} else {
return $default;
}
}
final public function getStr($name, $default = null) {
if (isset($this->requestData[$name])) {
return (string)$this->requestData[$name];
} else {
return $default;
}
}
final public function getArr($name, $default = array()) {
if (isset($this->requestData[$name]) &&
is_array($this->requestData[$name])) {
return $this->requestData[$name];
} else {
return $default;
}
}
final public function getExists($name) {
return array_key_exists($name, $this->requestData);
}
final public function isHTTPPost() {
return ($_SERVER['REQUEST_METHOD'] == 'POST');
}
final public function isAjax() {
return $this->getExists(self::TYPE_AJAX);
}
final public function isFormPost() {
return $this->getExists(self::TYPE_FORM) &&
$this->isHTTPPost() &&
$this->getUser()->validateCSRFToken($this->getStr('__csrf__'));
}
final public function getCookie($name, $default = null) {
return idx($_COOKIE, $name, $default);
}
final public function clearCookie($name) {
$this->setCookie($name, '', time() - (60 * 60 * 24 * 30));
}
final public function setCookie($name, $value, $expire = null) {
if ($expire === null) {
$expire = time() + (60 * 60 * 24 * 365 * 5);
}
setcookie(
$name,
$value,
$expire,
$path = '/',
$domain = '',
$secure = false,
$http_only = true);
}
final public function setUser($user) {
$this->user = $user;
return $this;
}
final public function getUser() {
return $this->user;
}
-
-
}
diff --git a/src/aphront/response/ajax/__init__.php b/src/aphront/response/ajax/__init__.php
index c0dd276bb7..fd1560d506 100644
--- a/src/aphront/response/ajax/__init__.php
+++ b/src/aphront/response/ajax/__init__.php
@@ -1,13 +1,13 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/base');
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_source('AphrontAjaxResponse.php');
diff --git a/src/applications/auth/controller/email/PhabricatorEmailLoginController.php b/src/applications/auth/controller/email/PhabricatorEmailLoginController.php
new file mode 100644
index 0000000000..e79998a254
--- /dev/null
+++ b/src/applications/auth/controller/email/PhabricatorEmailLoginController.php
@@ -0,0 +1,131 @@
+<?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.
+ */
+
+class PhabricatorEmailLoginController extends PhabricatorAuthController {
+
+ public function shouldRequireLogin() {
+ return false;
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+
+ $e_email = true;
+ $e_captcha = true;
+ $errors = array();
+
+ if ($request->isFormPost()) {
+ $e_email = null;
+ $e_captcha = 'Again';
+
+ $captcha_ok = AphrontFormRecaptchaControl::processCaptcha($request);
+ if (!$captcha_ok) {
+ $errors[] = "Captcha response is incorrect, try again.";
+ $e_captcha = 'Invalid';
+ }
+
+ $email = $request->getStr('email');
+ if (!strlen($email)) {
+ $errors[] = "You must provide an email address.";
+ $e_email = 'Required';
+ }
+
+ if (!$errors) {
+ // NOTE: Don't validate the email unless the captcha is good; this makes
+ // it expensive to fish for valid email addresses while giving the user
+ // a better error if they goof their email.
+
+ $target_user = id(new PhabricatorUser())->loadOneWhere(
+ 'email = %s',
+ $email);
+
+ if (!$target_user) {
+ $errors[] = "There is no account associated with that email address.";
+ $e_email = "Invalid";
+ }
+
+ if (!$errors) {
+ $etoken = $target_user->generateEmailToken();
+
+ $mail = new PhabricatorMetaMTAMail();
+ $mail->setSubject('Phabricator Email Authentication');
+ $mail->addTos(
+ array(
+ $target_user->getEmail(),
+ ));
+ $mail->setBody(
+ "blah blah blah ".
+ PhabricatorEnv::getURI('/login/etoken/'.$etoken.'/').'?email='.phutil_escape_uri($target_user->getEmail()));
+ $mail->save();
+
+ $view = new AphrontRequestFailureView();
+ $view->setHeader('Check Your Email');
+ $view->appendChild(
+ '<p>An email has been sent with a link you can use to login.</p>');
+ return $this->buildStandardPageResponse(
+ $view,
+ array(
+ 'title' => 'Email Sent',
+ ));
+ }
+ }
+
+ }
+
+ $email_auth = new AphrontFormView();
+ $email_auth
+ ->setAction('/login/email/')
+ ->setUser($request->getUser())
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setLabel('Email')
+ ->setName('email')
+ ->setValue($request->getStr('email'))
+ ->setError($e_email))
+ ->appendChild(
+ id(new AphrontFormRecaptchaControl())
+ ->setLabel('Captcha')
+ ->setError($e_captcha))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue('Send Email'));
+
+ $error_view = null;
+ if ($errors) {
+ $error_view = new AphrontErrorView();
+ $error_view->setTitle('Login Error');
+ $error_view->setErrors($errors);
+ }
+
+
+ $panel = new AphrontPanelView();
+ $panel->setWidth(AphrontPanelView::WIDTH_FORM);
+ $panel->appendChild('<h1>Forgot Password / Email Login</h1>');
+ $panel->appendChild($email_auth);
+
+ return $this->buildStandardPageResponse(
+ array(
+ $error_view,
+ $panel,
+ ),
+ array(
+ 'title' => 'Create New Account',
+ ));
+ }
+
+}
diff --git a/src/applications/auth/controller/facebookconnect/__init__.php b/src/applications/auth/controller/email/__init__.php
similarity index 64%
copy from src/applications/auth/controller/facebookconnect/__init__.php
copy to src/applications/auth/controller/email/__init__.php
index 7c02260f35..72d4c63071 100644
--- a/src/applications/auth/controller/facebookconnect/__init__.php
+++ b/src/applications/auth/controller/email/__init__.php
@@ -1,22 +1,24 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/auth/controller/base');
-phutil_require_module('phabricator', 'applications/files/storage/file');
+phutil_require_module('phabricator', 'applications/metamta/storage/mail');
phutil_require_module('phabricator', 'applications/people/storage/user');
+phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/form/base');
+phutil_require_module('phabricator', 'view/form/control/recaptcha');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/page/failure');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
-phutil_require_source('PhabricatorFacebookConnectController.php');
+phutil_require_source('PhabricatorEmailLoginController.php');
diff --git a/src/applications/auth/controller/emailtoken/PhabricatorEmailTokenController.php b/src/applications/auth/controller/emailtoken/PhabricatorEmailTokenController.php
new file mode 100644
index 0000000000..abfd26e89e
--- /dev/null
+++ b/src/applications/auth/controller/emailtoken/PhabricatorEmailTokenController.php
@@ -0,0 +1,137 @@
+<?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.
+ */
+
+class PhabricatorEmailTokenController extends PhabricatorAuthController {
+
+ private $token;
+
+ public function shouldRequireLogin() {
+ return false;
+ }
+
+ public function willProcessRequest(array $data) {
+ $this->token = $data['token'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+
+ $token = $this->token;
+ $email = $request->getStr('email');
+
+ $target_user = id(new PhabricatorUser())->loadOneWhere(
+ 'email = %s',
+ $email);
+
+ if (!$target_user || !$target_user->validateEmailToken($token)) {
+ $view = new AphrontRequestFailureView();
+ $view->setHeader('Unable to Login');
+ $view->appendChild(
+ '<p>The authentication information in the link you clicked is '.
+ 'invalid or out of date. Make sure you are copy-and-pasting the '.
+ 'entire link into your browser. You can try again, or request '.
+ 'a new email.</p>');
+ $view->appendChild(
+ '<div class="aphront-failure-continue">'.
+ '<a class="button" href="/login/email/">Send Another Email</a>'.
+ '</div>');
+ return $this->buildStandardPageResponse(
+ $view,
+ array(
+ 'title' => 'Email Sent',
+ ));
+ }
+
+ if ($request->getUser()->getPHID() != $target_user->getPHID()) {
+ $session_key = $target_user->establishSession('web');
+ $request->setCookie('phusr', $target_user->getUsername());
+ $request->setCookie('phsid', $session_key);
+ }
+
+ $errors = array();
+
+ $e_pass = true;
+ $e_confirm = true;
+
+ if ($request->isFormPost()) {
+ $e_pass = 'Error';
+ $e_confirm = 'Error';
+
+ $pass = $request->getStr('password');
+ $confirm = $request->getStr('confirm');
+
+ if (strlen($pass) < 3) {
+ $errors[] = 'That password is ridiculously short.';
+ }
+
+ if ($pass !== $confirm) {
+ $errors[] = "Passwords do not match.";
+ }
+
+ if (!$errors) {
+ $target_user->setPassword($pass);
+ $target_user->save();
+ return id(new AphrontRedirectResponse())
+ ->setURI('/');
+ }
+ }
+
+ if ($errors) {
+ $error_view = new AphrontErrorView();
+ $error_view->setTitle('Password Reset Failed');
+ $error_view->setErrors($errors);
+ } else {
+ $error_view = null;
+ }
+
+ $form = new AphrontFormView();
+ $form
+ ->setUser($target_user)
+ ->setAction('/login/etoken/'.$token.'/')
+ ->addHiddenInput('email', $email)
+ ->appendChild(
+ id(new AphrontFormPasswordControl())
+ ->setLabel('New Password')
+ ->setName('password')
+ ->setError($e_pass))
+ ->appendChild(
+ id(new AphrontFormPasswordControl())
+ ->setLabel('Confirm Password')
+ ->setName('confirm')
+ ->setError($e_confirm))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue('Reset Password')
+ ->addCancelButton('/', 'Skip'));
+
+ $panel = new AphrontPanelView();
+ $panel->setWidth(AphrontPanelView::WIDTH_FORM);
+ $panel->setHeader('Reset Password');
+ $panel->appendChild($form);
+
+ return $this->buildStandardPageResponse(
+ array(
+ $error_view,
+ $panel,
+ ),
+ array(
+ 'title' => 'Create New Account',
+ ));
+ }
+
+}
diff --git a/src/applications/auth/controller/facebookconnect/__init__.php b/src/applications/auth/controller/emailtoken/__init__.php
similarity index 76%
copy from src/applications/auth/controller/facebookconnect/__init__.php
copy to src/applications/auth/controller/emailtoken/__init__.php
index 7c02260f35..fd917cbcc1 100644
--- a/src/applications/auth/controller/facebookconnect/__init__.php
+++ b/src/applications/auth/controller/emailtoken/__init__.php
@@ -1,22 +1,21 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/auth/controller/base');
-phutil_require_module('phabricator', 'applications/files/storage/file');
phutil_require_module('phabricator', 'applications/people/storage/user');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/page/failure');
-phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
-phutil_require_source('PhabricatorFacebookConnectController.php');
+phutil_require_source('PhabricatorEmailTokenController.php');
diff --git a/src/applications/auth/controller/facebookconnect/PhabricatorFacebookConnectController.php b/src/applications/auth/controller/facebookauth/PhabricatorFacebookAuthController.php
similarity index 65%
rename from src/applications/auth/controller/facebookconnect/PhabricatorFacebookConnectController.php
rename to src/applications/auth/controller/facebookauth/PhabricatorFacebookAuthController.php
index 34b2116ea2..7f86928722 100644
--- a/src/applications/auth/controller/facebookconnect/PhabricatorFacebookConnectController.php
+++ b/src/applications/auth/controller/facebookauth/PhabricatorFacebookAuthController.php
@@ -1,207 +1,275 @@
<?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.
*/
-class PhabricatorFacebookConnectController extends PhabricatorAuthController {
+class PhabricatorFacebookAuthController extends PhabricatorAuthController {
public function shouldRequireLogin() {
return false;
}
public function processRequest() {
+ $auth_enabled = PhabricatorEnv::getEnvConfig('facebook.auth-enabled');
+ if (!$auth_enabled) {
+ return new Aphront400Response();
+ }
+
+ $diagnose_auth =
+ '<a href="/facebook-auth/diagnose/" class="button green">'.
+ 'Diagnose Facebook Auth Problems'.
+ '</a>';
+
$request = $this->getRequest();
if ($request->getStr('error')) {
- die("OMG ERROR");
+ $view = new AphrontRequestFailureView();
+ $view->setHeader('Facebook Auth Failed');
+ $view->appendChild(
+ '<p>'.
+ '<strong>Description:</strong> '.
+ phutil_escape_html($request->getStr('error_description')).
+ '</p>');
+ $view->appendChild(
+ '<p>'.
+ '<strong>Error:</strong> '.
+ phutil_escape_html($request->getStr('error')).
+ '</p>');
+ $view->appendChild(
+ '<p>'.
+ '<strong>Error Reason:</strong> '.
+ phutil_escape_html($request->getStr('error_reason')).
+ '</p>');
+ $view->appendChild(
+ '<div class="aphront-failure-continue">'.
+ '<a href="/login/" class="button">Continue</a>'.
+ '</div>');
+
+ return $this->buildStandardPageResponse(
+ $view,
+ array(
+ 'title' => 'Facebook Auth Failed',
+ ));
}
$token = $request->getStr('token');
if (!$token) {
+ $app_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
+ $app_secret = PhabricatorEnv::getEnvConfig('facebook.application-secret');
+ $redirect_uri = PhabricatorEnv::getURI('/facebook-auth/');
+
$code = $request->getStr('code');
- $auth_uri = 'https://graph.facebook.com/oauth/access_token'.
- '?client_id=184510521580034'.
- '&redirect_uri=http://local.aphront.com/facebook-connect/'.
- '&client_secret=OMGSECRETS'.
- '&code='.$code;
+ $auth_uri = new PhutilURI(
+ "https://graph.facebook.com/oauth/access_token");
+ $auth_uri->setQueryParams(
+ array(
+ 'client_id' => $app_id,
+ 'redirect_uri' => $redirect_uri,
+ 'client_secret' => $app_secret,
+ 'code' => $code,
+ ));
$response = @file_get_contents($auth_uri);
if ($response === false) {
- throw new Exception('failed to open oauth thing');
+ $view = new AphrontRequestFailureView();
+ $view->setHeader('Facebook Auth Failed');
+ $view->appendChild(
+ '<p>Unable to authenticate with Facebook. There are several reasons '.
+ 'this might happen:</p>'.
+ '<ul>'.
+ '<li>Phabricator may be configured with the wrong Application '.
+ 'Secret; or</li>'.
+ '<li>the Facebook OAuth access token may have expired; or</li>'.
+ '<li>Facebook may have revoked authorization for the '.
+ 'Application; or</li>'.
+ '<li>Facebook may be having technical problems.</li>'.
+ '</ul>'.
+ '<p>You can try again, or login using another method.</p>');
+ $view->appendChild(
+ '<div class="aphront-failure-continue">'.
+ $diagnose_auth.
+ '<a href="/login/" class="button">Continue</a>'.
+ '</div>');
+
+ return $this->buildStandardPageResponse(
+ $view,
+ array(
+ 'title' => 'Facebook Auth Failed',
+ ));
}
$data = array();
parse_str($response, $data);
$token = $data['access_token'];
}
$user_json = @file_get_contents('https://graph.facebook.com/me?access_token='.$token);
$user_data = json_decode($user_json, true);
$user_id = $user_data['id'];
$known_user = id(new PhabricatorUser())
->loadOneWhere('facebookUID = %d', $user_id);
if ($known_user) {
$session_key = $known_user->establishSession('web');
$request->setCookie('phusr', $known_user->getUsername());
$request->setCookie('phsid', $session_key);
return id(new AphrontRedirectResponse())
->setURI('/');
}
$current_user = $this->getRequest()->getUser();
if ($current_user->getPHID()) {
if ($current_user->getFacebookUID() &&
$current_user->getFacebookUID() != $user_id) {
throw new Exception(
"Your account is already associated with a Facebook user ID other ".
"than the one you just logged in with...?");
}
if ($request->isFormPost()) {
$current_user->setFacebookUID($user_id);
$current_user->save();
// TODO: ship them back to the 'account' page or whatever?
return id(new AphrontRedirectResponse())
->setURI('/');
}
$ph_account = $current_user->getUsername();
$fb_account = phutil_escape_html($user_data['name']);
$form = new AphrontFormView();
$form
->addHiddenInput('token', $token)
->setUser($request->getUser())
- ->setAction('/facebook-connect/')
+ ->setAction('/facebook-auth/')
->appendChild(
'<p class="aphront-form-view-instructions">Do you want to link your '.
"existing Phabricator account (<strong>{$ph_account}</strong>) ".
"with your Facebook account (<strong>{$fb_account}</strong>) so ".
- "you can login with Facebook Connect?")
+ "you can login with Facebook?")
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Link Accounts')
->addCancelButton('/login/'));
$panel = new AphrontPanelView();
$panel->setHeader('Link Facebook Account');
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
return $this->buildStandardPageResponse(
$panel,
array(
'title' => 'Link Facebook Account',
));
}
$errors = array();
$e_username = true;
$user = new PhabricatorUser();
$matches = null;
if (preg_match('@/([a-zA-Z0-9]+)$@', $user_data['link'], $matches)) {
$user->setUsername($matches[1]);
}
if ($request->isFormPost()) {
$username = $request->getStr('username');
if (!strlen($username)) {
$e_username = 'Required';
$errors[] = 'Username is required.';
} else if (!preg_match('/^[a-zA-Z0-9]+$/', $username, $matches)) {
$e_username = 'Invalid';
$errors[] = 'Username may only contain letters and numbers.';
}
$user->setUsername($username);
$user->setFacebookUID($user_id);
$user->setEmail($user_data['email']);
if (!$errors) {
$image = @file_get_contents('https://graph.facebook.com/me/picture?access_token='.$token);
$file = PhabricatorFile::newFromFileData(
$image,
array(
'name' => 'fbprofile.jpg'
));
$user->setProfileImagePHID($file->getPHID());
$user->setRealName($user_data['name']);
try {
$user->save();
$session_key = $user->establishSession('web');
$request->setCookie('phusr', $user->getUsername());
$request->setCookie('phsid', $session_key);
return id(new AphrontRedirectResponse())->setURI('/');
} catch (AphrontQueryDuplicateKeyException $exception) {
$key = $exception->getDuplicateKey();
if ($key == 'userName') {
$e_username = 'Duplicate';
$errors[] = 'That username is not unique.';
} else {
throw $exception;
}
}
}
}
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
- $error_view->setTitle('Facebook Connect Failed');
+ $error_view->setTitle('Facebook Auth Failed');
$error_view->setErrors($errors);
}
$form = new AphrontFormView();
$form
->addHiddenInput('token', $token)
->setUser($request->getUser())
- ->setAction('/facebook-connect/')
+ ->setAction('/facebook-auth/')
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Username')
->setName('username')
->setValue($user->getUsername())
->setError($e_username))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Create Account'));
$panel = new AphrontPanelView();
$panel->setHeader('Create New Account');
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
return $this->buildStandardPageResponse(
array(
$error_view,
$panel,
),
array(
'title' => 'Create New Account',
));
}
}
diff --git a/src/applications/auth/controller/facebookconnect/__init__.php b/src/applications/auth/controller/facebookauth/__init__.php
similarity index 71%
rename from src/applications/auth/controller/facebookconnect/__init__.php
rename to src/applications/auth/controller/facebookauth/__init__.php
index 7c02260f35..f5b4a8f1a9 100644
--- a/src/applications/auth/controller/facebookconnect/__init__.php
+++ b/src/applications/auth/controller/facebookauth/__init__.php
@@ -1,22 +1,25 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
+phutil_require_module('phabricator', 'aphront/response/400');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/auth/controller/base');
phutil_require_module('phabricator', 'applications/files/storage/file');
phutil_require_module('phabricator', 'applications/people/storage/user');
+phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/page/failure');
phutil_require_module('phutil', 'markup');
+phutil_require_module('phutil', 'parser/uri');
phutil_require_module('phutil', 'utils');
-
-phutil_require_source('PhabricatorFacebookConnectController.php');
+phutil_require_source('PhabricatorFacebookAuthController.php');
diff --git a/src/applications/auth/controller/facebookauth/diagnostics/PhabricatorFacebookAuthDiagnosticsController.php b/src/applications/auth/controller/facebookauth/diagnostics/PhabricatorFacebookAuthDiagnosticsController.php
new file mode 100644
index 0000000000..f880e6eadf
--- /dev/null
+++ b/src/applications/auth/controller/facebookauth/diagnostics/PhabricatorFacebookAuthDiagnosticsController.php
@@ -0,0 +1,230 @@
+<?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.
+ */
+
+class PhabricatorFacebookAuthDiagnosticsController
+ extends PhabricatorAuthController {
+
+ public function shouldRequireLogin() {
+ return false;
+ }
+
+ public function processRequest() {
+
+ $auth_enabled = PhabricatorEnv::getEnvConfig('facebook.auth-enabled');
+ $app_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
+ $app_secret = PhabricatorEnv::getEnvConfig('facebook.application-secret');
+
+ $res_ok = '<strong style="color: #00aa00;">OK</strong>';
+ $res_no = '<strong style="color: #aa0000;">NO</strong>';
+ $res_na = '<strong style="color: #999999;">N/A</strong>';
+
+ $results = array();
+
+ if (!$auth_enabled) {
+ $results['facebook.auth-enabled'] = array(
+ $res_no,
+ 'false',
+ 'Facebook authentication is disabled in the configuration. Edit the '.
+ 'environmental configuration to enable "facebook.auth-enabled".');
+ } else {
+ $results['facebook.auth-enabled'] = array(
+ $res_ok,
+ 'true',
+ 'Facebook authentication is enabled.');
+ }
+
+ if (!$app_id) {
+ $results['facebook.application-id'] = array(
+ $res_no,
+ null,
+ 'No Facebook Application ID is configured. Edit the environmental '.
+ 'configuration to specify an application ID in '.
+ '"facebook.application-id". To generate an ID, sign into Facebook, '.
+ 'install the "Developer" application, and use it to create a new '.
+ 'Facebook application.');
+ } else {
+ $results['facebook.application-id'] = array(
+ $res_ok,
+ $app_id,
+ 'Application ID is set.');
+ }
+
+ if (!$app_secret) {
+ $results['facebook.application-secret'] = array(
+ $res_no,
+ null,
+ 'No Facebook Application secret is configured. Edit the environmental '.
+ 'configuration to specify an Application Secret, in '.
+ '"facebook.application-secret". You can find the application secret '.
+ 'in the Facebook "Developer" application on Facebook.');
+ } else {
+ $results['facebook.application-secret'] = array(
+ $res_ok,
+ "It's a secret!",
+ 'Application secret is set.');
+ }
+
+ $timeout = stream_context_create(
+ array(
+ 'http' => array(
+ 'ignore_errors' => true,
+ 'timeout' => 5,
+ ),
+ ));
+ $timeout_strict = stream_context_create(
+ array(
+ 'http' => array(
+ 'timeout' => 5,
+ ),
+ ));
+
+ $internet = @file_get_contents("http://google.com/", false, $timeout);
+ if ($internet === false) {
+ $results['internet'] = array(
+ $res_no,
+ null,
+ 'Unable to make an HTTP request to Google. Check your outbound '.
+ 'internet connection and firewall/filtering settings.');
+ } else {
+ $results['internet'] = array(
+ $res_ok,
+ null,
+ 'Internet seems OK.');
+ }
+
+ $facebook = @file_get_contents("http://facebook.com/", false, $timeout);
+ if ($facebook === false) {
+ $results['facebook.com'] = array(
+ $res_no,
+ null,
+ 'Unable to make an HTTP request to facebook.com. Facebook may be '.
+ 'down or inaccessible.');
+ } else {
+ $results['facebook.com'] = array(
+ $res_ok,
+ null,
+ 'Made a request to facebook.com.');
+ }
+
+ $graph = @file_get_contents(
+ "https://graph.facebook.com/me",
+ false,
+ $timeout);
+ if ($graph === false) {
+ $results['Facebook Graph'] = array(
+ $res_no,
+ null,
+ "Unable to make an HTTPS request to graph.facebook.com. ".
+ "The Facebook graph may be down or inaccessible.");
+ } else {
+ $results['Facebook Graph'] = array(
+ $res_ok,
+ null,
+ 'Made a request to graph.facebook.com.');
+ }
+
+ $test_uri = new PhutilURI('https://graph.facebook.com/oauth/access_token');
+ $test_uri->setQueryParams(
+ array(
+ 'client_id' => $app_id,
+ 'client_secret' => $app_secret,
+ 'grant_type' => 'client_credentials',
+ ));
+
+ $token_value = @file_get_contents($test_uri, false, $timeout);
+ $token_strict = @file_get_contents($test_uri, false, $timeout_strict);
+ if ($token_value === false) {
+ $results['App Login'] = array(
+ $res_no,
+ null,
+ "Unable to perform an application login with your Application ID and ".
+ "Application Secret. You may have mistyped or misconfigured them; ".
+ "Facebook may have revoked your authorization; or Facebook may be ".
+ "having technical problems.");
+ } else {
+ if ($token_strict) {
+ $results['App Login'] = array(
+ $res_ok,
+ $token_strict,
+ "Raw application login to Facebook works.");
+ } else {
+ $data = json_decode($token_value, true);
+ if (!is_array($data)) {
+ $results['App Login'] = array(
+ $res_no,
+ $token_value,
+ "Application Login failed but the graph server did not respond ".
+ "with valid JSON error information. Facebook may be experiencing ".
+ "technical problems.");
+ } else {
+ $results['App Login'] = array(
+ $res_no,
+ null,
+ "Application Login failed with error: ".$token_value);
+ }
+ }
+ }
+
+ return $this->renderResults($results);
+ }
+
+ private function renderResults($results) {
+
+ $rows = array();
+ foreach ($results as $key => $result) {
+ $rows[] = array(
+ phutil_escape_html($key),
+ $result[0],
+ phutil_escape_html($result[1]),
+ phutil_escape_html($result[2]),
+ );
+ }
+
+ $table_view = new AphrontTableView($rows);
+ $table_view->setHeaders(
+ array(
+ 'Test',
+ 'Result',
+ 'Value',
+ 'Details',
+ ));
+ $table_view->setColumnClasses(
+ array(
+ null,
+ null,
+ null,
+ 'wide',
+ ));
+
+ $panel_view = new AphrontPanelView();
+ $panel_view->setHeader('Facebook Auth Diagnostics');
+ $panel_view->appendChild(
+ '<p class="aphront-panel-instructions">These tests may be able to '.
+ 'help diagnose the root cause of problems you experience with '.
+ 'Facebook Authentication. Reload the page to run the tests again.</p>');
+ $panel_view->appendChild($table_view);
+
+ return $this->buildStandardPageResponse(
+ $panel_view,
+ array(
+ 'title' => 'Facebook Auth Diagnostics',
+ ));
+
+ }
+
+}
diff --git a/src/applications/auth/controller/facebookauth/diagnostics/__init__.php b/src/applications/auth/controller/facebookauth/diagnostics/__init__.php
new file mode 100644
index 0000000000..4603969d31
--- /dev/null
+++ b/src/applications/auth/controller/facebookauth/diagnostics/__init__.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/auth/controller/base');
+phutil_require_module('phabricator', 'infrastructure/env');
+phutil_require_module('phabricator', 'view/control/table');
+phutil_require_module('phabricator', 'view/layout/panel');
+
+phutil_require_module('phutil', 'markup');
+phutil_require_module('phutil', 'parser/uri');
+
+
+phutil_require_source('PhabricatorFacebookAuthDiagnosticsController.php');
diff --git a/src/applications/auth/controller/login/PhabricatorLoginController.php b/src/applications/auth/controller/login/PhabricatorLoginController.php
index 4fb14c8d5c..dc871ccb44 100644
--- a/src/applications/auth/controller/login/PhabricatorLoginController.php
+++ b/src/applications/auth/controller/login/PhabricatorLoginController.php
@@ -1,123 +1,134 @@
<?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.
*/
class PhabricatorLoginController extends PhabricatorAuthController {
public function shouldRequireLogin() {
return false;
}
public function processRequest() {
$request = $this->getRequest();
$error = false;
$username = $request->getCookie('phusr');
if ($request->isFormPost()) {
$username = $request->getStr('username');
$user = id(new PhabricatorUser())->loadOneWhere(
'username = %s',
$username);
- $user->setPassword('asdf');
- $user->save();
-
$okay = false;
if ($user) {
if ($user->comparePassword($request->getStr('password'))) {
$session_key = $user->establishSession('web');
$request->setCookie('phusr', $user->getUsername());
$request->setCookie('phsid', $session_key);
return id(new AphrontRedirectResponse())
->setURI('/');
}
}
if (!$okay) {
$request->clearCookie('phusr');
$request->clearCookie('phsid');
}
$error = true;
}
$error_view = null;
if ($error) {
$error_view = new AphrontErrorView();
$error_view->setTitle('Bad username/password.');
}
$form = new AphrontFormView();
$form
->setUser($request->getUser())
->setAction('/login/')
->appendChild(
id(new AphrontFormTextControl())
- ->setLabel('Username')
+ ->setLabel('Username/Email')
->setName('username')
->setValue($username))
->appendChild(
- id(new AphrontFormTextControl())
+ id(new AphrontFormPasswordControl())
->setLabel('Password')
- ->setName('password'))
+ ->setName('password')
+ ->setCaption(
+ '<a href="/login/email/">Forgot your password? / Email Login</a>'))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Login'));
$panel = new AphrontPanelView();
$panel->setHeader('Phabricator Login');
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
-
- // TODO: Hardcoded junk
- $connect_uri = "https://www.facebook.com/dialog/oauth";
-
- $user = $request->getUser();
-
- $facebook_connect = new AphrontFormView();
- $facebook_connect
- ->setAction($connect_uri)
- ->addHiddenInput('client_id', 184510521580034)
- ->addHiddenInput('redirect_uri', 'http://local.aphront.com/facebook-connect/')
- ->addHiddenInput('scope', 'email')
- ->addHiddenInput('state', $user->getCSRFToken())
- ->setUser($request->getUser())
- ->setMethod('GET')
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue("Login with Facebook Connect \xC2\xBB"));
-
- $panel->appendChild('<br /><h1>Login with Facebook</h1>');
- $panel->appendChild($facebook_connect);
+ $fbauth_enabled = PhabricatorEnv::getEnvConfig('facebook.auth-enabled');
+ if ($fbauth_enabled) {
+ $auth_uri = new PhutilURI("https://www.facebook.com/dialog/oauth");
+
+ $user = $request->getUser();
+
+ $redirect_uri = PhabricatorEnv::getURI('/facebook-auth/');
+ $app_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
+
+ // TODO: In theory we should use 'state' to prevent CSRF, but the total
+ // effect of the CSRF attack is that an attacker can cause a user to login
+ // to Phabricator if they're already logged into Facebook. This does not
+ // seem like the most severe threat in the world, and generating CSRF for
+ // logged-out users is vaugely tricky.
+
+ $facebook_auth = new AphrontFormView();
+ $facebook_auth
+ ->setAction($auth_uri)
+ ->addHiddenInput('client_id', $app_id)
+ ->addHiddenInput('redirect_uri', $redirect_uri)
+ ->addHiddenInput('scope', 'email')
+ ->setUser($request->getUser())
+ ->setMethod('GET')
+ ->appendChild(
+ '<p class="aphront-form-instructions">Login or register for '.
+ 'Phabricator using your Facebook account.</p>')
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue("Login with Facebook \xC2\xBB"));
+
+ $panel->appendChild('<br /><h1>Login with Facebook</h1>');
+ $panel->appendChild($facebook_auth);
+ }
return $this->buildStandardPageResponse(
array(
$error_view,
$panel,
),
array(
'title' => 'Login',
));
}
}
diff --git a/src/applications/auth/controller/login/__init__.php b/src/applications/auth/controller/login/__init__.php
index c3c5e62c3b..85ec5fcd3e 100644
--- a/src/applications/auth/controller/login/__init__.php
+++ b/src/applications/auth/controller/login/__init__.php
@@ -1,20 +1,22 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/auth/controller/base');
phutil_require_module('phabricator', 'applications/people/storage/user');
+phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phutil', 'parser/uri');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorLoginController.php');
diff --git a/src/applications/differential/controller/base/__init__.php b/src/applications/differential/controller/base/__init__.php
index 5e0ce69e00..015845d45e 100644
--- a/src/applications/differential/controller/base/__init__.php
+++ b/src/applications/differential/controller/base/__init__.php
@@ -1,16 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/webpage');
phutil_require_module('phabricator', 'applications/base/controller/base');
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phutil', 'utils');
phutil_require_source('DifferentialController.php');
diff --git a/src/applications/differential/view/changesetdetailview/__init__.php b/src/applications/differential/view/changesetdetailview/__init__.php
index 575d0c87f4..4e50ea0f06 100644
--- a/src/applications/differential/view/changesetdetailview/__init__.php
+++ b/src/applications/differential/view/changesetdetailview/__init__.php
@@ -1,16 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
-phutil_require_module('phabricator', 'infratructure/javelin/markup');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/javelin/markup');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('DifferentialChangesetDetailView.php');
diff --git a/src/applications/differential/view/changesetlistview/__init__.php b/src/applications/differential/view/changesetlistview/__init__.php
index f7d535542a..9f040ff17f 100644
--- a/src/applications/differential/view/changesetlistview/__init__.php
+++ b/src/applications/differential/view/changesetlistview/__init__.php
@@ -1,19 +1,19 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/differential/constants/changetype');
phutil_require_module('phabricator', 'applications/differential/view/changesetdetailview');
-phutil_require_module('phabricator', 'infratructure/celerity/api');
-phutil_require_module('phabricator', 'infratructure/javelin/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/javelin/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('DifferentialChangesetListView.php');
diff --git a/src/applications/differential/view/difftableofcontents/__init__.php b/src/applications/differential/view/difftableofcontents/__init__.php
index da5da976d1..a29530d370 100644
--- a/src/applications/differential/view/difftableofcontents/__init__.php
+++ b/src/applications/differential/view/difftableofcontents/__init__.php
@@ -1,16 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/differential/constants/changetype');
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('DifferentialDiffTableOfContentsView.php');
diff --git a/src/applications/differential/view/revisioncomment/__init__.php b/src/applications/differential/view/revisioncomment/__init__.php
index 9542bcce85..2f19fad814 100644
--- a/src/applications/differential/view/revisioncomment/__init__.php
+++ b/src/applications/differential/view/revisioncomment/__init__.php
@@ -1,16 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/differential/constants/action');
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('DifferentialRevisionCommentView.php');
diff --git a/src/applications/differential/view/revisioncommentlist/__init__.php b/src/applications/differential/view/revisioncommentlist/__init__.php
index 2e8410cce2..446ab1fa36 100644
--- a/src/applications/differential/view/revisioncommentlist/__init__.php
+++ b/src/applications/differential/view/revisioncommentlist/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/differential/parser/markup');
phutil_require_module('phabricator', 'applications/differential/view/revisioncomment');
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_source('DifferentialRevisionCommentListView.php');
diff --git a/src/applications/differential/view/revisiondetail/__init__.php b/src/applications/differential/view/revisiondetail/__init__.php
index 9eb662528a..6d159f3325 100644
--- a/src/applications/differential/view/revisiondetail/__init__.php
+++ b/src/applications/differential/view/revisiondetail/__init__.php
@@ -1,16 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('DifferentialRevisionDetailView.php');
diff --git a/src/applications/differential/view/revisionupdatehistory/__init__.php b/src/applications/differential/view/revisionupdatehistory/__init__.php
index 6e88bf893d..513616c042 100644
--- a/src/applications/differential/view/revisionupdatehistory/__init__.php
+++ b/src/applications/differential/view/revisionupdatehistory/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('DifferentialRevisionUpdateHistoryView.php');
diff --git a/src/applications/directory/controller/main/__init__.php b/src/applications/directory/controller/main/__init__.php
index a059f07cff..e9a5b9d06c 100644
--- a/src/applications/directory/controller/main/__init__.php
+++ b/src/applications/directory/controller/main/__init__.php
@@ -1,18 +1,18 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/directory/controller/base');
phutil_require_module('phabricator', 'applications/directory/storage/category');
phutil_require_module('phabricator', 'applications/directory/storage/item');
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorDirectoryMainController.php');
diff --git a/src/applications/people/storage/user/PhabricatorUser.php b/src/applications/people/storage/user/PhabricatorUser.php
index fba75bbcb8..abef89f7a4 100644
--- a/src/applications/people/storage/user/PhabricatorUser.php
+++ b/src/applications/people/storage/user/PhabricatorUser.php
@@ -1,121 +1,145 @@
<?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.
*/
class PhabricatorUser extends PhabricatorUserDAO {
const PHID_TYPE = 'USER';
protected $phid;
protected $userName;
protected $realName;
protected $email;
protected $passwordSalt;
protected $passwordHash;
protected $facebookUID;
protected $profileImagePHID;
private $sessionKey;
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(self::PHID_TYPE);
}
public function setPassword($password) {
$this->setPasswordSalt(md5(mt_rand()));
$hash = $this->hashPassword($password);
$this->setPasswordHash($hash);
return $this;
}
public function comparePassword($password) {
$password = $this->hashPassword($password);
return ($password === $this->getPasswordHash());
}
private function hashPassword($password) {
$password = $this->getUsername().
$password.
$this->getPHID().
$this->getPasswordSalt();
for ($ii = 0; $ii < 1000; $ii++) {
$password = md5($password);
}
return $password;
}
- const CSRF_CYCLE_FREQUENCY = 3600;
-
- public function getCSRFToken() {
- return $this->generateCSRFToken(time());
+ const CSRF_CYCLE_FREQUENCY = 3600;
+ const CSRF_TOKEN_LENGTH = 16;
+
+ const EMAIL_CYCLE_FREQUENCY = 86400;
+ const EMAIL_TOKEN_LENGTH = 24;
+
+ public function getCSRFToken($offset = 0) {
+ return $this->generateToken(
+ time() + (self::CSRF_CYCLE_FREQUENCY * $offset),
+ self::CSRF_CYCLE_FREQUENCY,
+ PhabricatorEnv::getEnvConfig('phabricator.csrf-key'),
+ self::CSRF_TOKEN_LENGTH);
}
public function validateCSRFToken($token) {
for ($ii = -1; $ii <= 1; $ii++) {
- $time = time() + (self::CSRF_CYCLE_FREQUENCY * $ii);
- $valid = $this->generateCSRFToken($time);
+ $valid = $this->getCSRFToken($ii);
if ($token == $valid) {
return true;
}
}
return false;
}
- private function generateCSRFToken($epoch) {
- $time_block = floor($epoch / (60 * 60));
- // TODO: this should be a secret lolol
- $key = '0b7ec0592e0a2829d8b71df2fa269b2c6172eca3';
+ private function generateToken($epoch, $frequency, $key, $len) {
+ $time_block = floor($epoch / $frequency);
$vec = $this->getPHID().$this->passwordHash.$key.$time_block;
- return substr(md5($vec), 0, 16);
+ return substr(sha1($vec), 0, $len);
}
public function establishSession($session_type) {
$conn_w = $this->establishConnection('w');
$urandom = fopen('/dev/urandom', 'r');
if (!$urandom) {
throw new Exception("Failed to open /dev/urandom!");
}
+
$entropy = fread($urandom, 20);
if (strlen($entropy) != 20) {
throw new Exception("Failed to read /dev/urandom!");
}
$session_key = sha1($entropy);
queryfx(
$conn_w,
'INSERT INTO phabricator_session '.
'(userPHID, type, sessionKey, sessionStart)'.
' VALUES '.
'(%s, %s, %s, UNIX_TIMESTAMP()) '.
'ON DUPLICATE KEY UPDATE '.
'sessionKey = VALUES(sessionKey), '.
'sessionStart = VALUES(sessionStart)',
$this->getPHID(),
$session_type,
$session_key);
return $session_key;
}
+ public function generateEmailToken($offset = 0) {
+ return $this->generateToken(
+ time() + ($offset * self::EMAIL_CYCLE_FREQUENCY),
+ self::EMAIL_CYCLE_FREQUENCY,
+ PhabricatorEnv::getEnvConfig('phabricator.csrf-key').$this->getEmail(),
+ self::EMAIL_TOKEN_LENGTH);
+ }
+
+ public function validateEmailToken($token) {
+ for ($ii = -1; $ii <= 1; $ii++) {
+ $valid = $this->generateEmailToken($ii);
+ if ($token == $valid) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
diff --git a/src/applications/people/storage/user/__init__.php b/src/applications/people/storage/user/__init__.php
index 6b89e2b125..ff97486c50 100644
--- a/src/applications/people/storage/user/__init__.php
+++ b/src/applications/people/storage/user/__init__.php
@@ -1,14 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/people/storage/base');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
+phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_source('PhabricatorUser.php');
diff --git a/src/infratructure/celerity/api/CelerityAPI.php b/src/infrastructure/celerity/api/CelerityAPI.php
similarity index 100%
rename from src/infratructure/celerity/api/CelerityAPI.php
rename to src/infrastructure/celerity/api/CelerityAPI.php
diff --git a/src/infratructure/celerity/api/__init__.php b/src/infrastructure/celerity/api/__init__.php
similarity index 66%
rename from src/infratructure/celerity/api/__init__.php
rename to src/infrastructure/celerity/api/__init__.php
index c05435461a..762576517c 100644
--- a/src/infratructure/celerity/api/__init__.php
+++ b/src/infrastructure/celerity/api/__init__.php
@@ -1,12 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/response');
+phutil_require_module('phabricator', 'infrastructure/celerity/response');
phutil_require_source('CelerityAPI.php');
diff --git a/src/infratructure/celerity/controller/CelerityResourceController.php b/src/infrastructure/celerity/controller/CelerityResourceController.php
similarity index 99%
rename from src/infratructure/celerity/controller/CelerityResourceController.php
rename to src/infrastructure/celerity/controller/CelerityResourceController.php
index 198a23cc04..81ffbe8bdf 100644
--- a/src/infratructure/celerity/controller/CelerityResourceController.php
+++ b/src/infrastructure/celerity/controller/CelerityResourceController.php
@@ -1,85 +1,85 @@
<?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.
*/
class CelerityResourceController extends AphrontController {
-
+
private $path;
private $hash;
private $package;
-
+
public function willProcessRequest(array $data) {
$this->path = $data['path'];
$this->hash = $data['hash'];
$this->package = !empty($data['package']);
}
public function processRequest() {
$path = $this->path;
// Sanity checking to keep this from exposing anything sensitive.
$path = preg_replace('@(//|\\.\\.)@', '', $path);
$matches = null;
if (!preg_match('/\.(css|js)$/', $path, $matches)) {
throw new Exception("Only CSS and JS resources may be served.");
}
-
+
$type = $matches[1];
$root = dirname(phutil_get_library_root('phabricator'));
if ($this->package) {
$map = CelerityResourceMap::getInstance();
$paths = $map->resolvePackage($this->hash);
if (!$paths) {
return new Aphront404Response();
}
-
+
try {
$data = array();
foreach ($paths as $path) {
$data[] = Filesystem::readFile($root.'/webroot/'.$path);
}
$data = implode("\n\n", $data);
} catch (Exception $ex) {
return new Aphront404Response();
}
} else {
try {
$data = Filesystem::readFile($root.'/webroot/'.$path);
} catch (Exception $ex) {
return new Aphront404Response();
}
}
$response = new AphrontFileResponse();
$response->setContent($data);
switch ($type) {
case 'css':
$response->setMimeType("text/css; charset=utf-8");
break;
case 'js':
$response->setMimeType("text/javascript; charset=utf-8");
break;
}
-
+
$response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
return $response;
}
}
diff --git a/src/infratructure/celerity/controller/__init__.php b/src/infrastructure/celerity/controller/__init__.php
similarity index 74%
rename from src/infratructure/celerity/controller/__init__.php
rename to src/infrastructure/celerity/controller/__init__.php
index c31e65c785..47494296c7 100644
--- a/src/infratructure/celerity/controller/__init__.php
+++ b/src/infrastructure/celerity/controller/__init__.php
@@ -1,16 +1,18 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/controller');
+phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/file');
+phutil_require_module('phabricator', 'infrastructure/celerity/map');
phutil_require_module('phutil', 'filesystem');
phutil_require_module('phutil', 'moduleutils');
phutil_require_source('CelerityResourceController.php');
diff --git a/src/infratructure/celerity/map/CelerityResourceMap.php b/src/infrastructure/celerity/map/CelerityResourceMap.php
similarity index 99%
rename from src/infratructure/celerity/map/CelerityResourceMap.php
rename to src/infrastructure/celerity/map/CelerityResourceMap.php
index 6ea9d8bdb9..a6ca2f22d3 100644
--- a/src/infratructure/celerity/map/CelerityResourceMap.php
+++ b/src/infrastructure/celerity/map/CelerityResourceMap.php
@@ -1,116 +1,116 @@
<?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.
*/
final class CelerityResourceMap {
private static $instance;
private $resourceMap;
private $packageMap;
public static function getInstance() {
if (empty(self::$instance)) {
self::$instance = new CelerityResourceMap();
$root = phutil_get_library_root('phabricator');
$ok = @include_once $root.'/__celerity_resource_map__.php';
if (!$ok) {
throw new Exception("Failed to load Celerity resource map!");
}
}
return self::$instance;
}
public function setResourceMap($resource_map) {
$this->resourceMap = $resource_map;
return $this;
}
public function resolveResources(array $symbols) {
$map = array();
foreach ($symbols as $symbol) {
if (!empty($map[$symbol])) {
continue;
}
$this->resolveResource($map, $symbol);
}
return $map;
}
private function resolveResource(array &$map, $symbol) {
if (empty($this->resourceMap[$symbol])) {
throw new Exception(
"Attempting to resolve unknown resource, '{$symbol}'.");
}
$info = $this->resourceMap[$symbol];
foreach ($info['requires'] as $requires) {
if (!empty($map[$requires])) {
continue;
}
$this->resolveResource($map, $requires);
}
$map[$symbol] = $info;
}
-
+
public function setPackageMap($package_map) {
$this->packageMap = $package_map;
}
-
+
public function packageResources(array $resolved_map) {
$packaged = array();
$handled = array();
foreach ($resolved_map as $symbol => $info) {
if (isset($handled[$symbol])) {
continue;
}
if (empty($this->packageMap['reverse'][$symbol])) {
$packaged[$symbol] = $info;
} else {
$package = $this->packageMap['reverse'][$symbol];
$package_info = $this->packageMap['packages'][$package];
$packaged[$package_info['name']] = $package_info;
foreach ($package_info['symbols'] as $symbol) {
$handled[$symbol] = true;
}
}
}
return $packaged;
}
-
+
public function resolvePackage($package_hash) {
$package = idx($this->packageMap['packages'], $package_hash);
if (!$package) {
return null;
}
-
+
$paths = array();
foreach ($package['symbols'] as $symbol) {
$paths[] = $this->resourceMap[$symbol]['disk'];
}
-
+
return $paths;
}
}
function celerity_register_resource_map(array $map, array $package_map) {
$instance = CelerityResourceMap::getInstance();
$instance->setResourceMap($map);
$instance->setPackageMap($package_map);
}
diff --git a/src/infratructure/celerity/map/__init__.php b/src/infrastructure/celerity/map/__init__.php
similarity index 82%
copy from src/infratructure/celerity/map/__init__.php
copy to src/infrastructure/celerity/map/__init__.php
index e2362e7274..d34da6d1be 100644
--- a/src/infratructure/celerity/map/__init__.php
+++ b/src/infrastructure/celerity/map/__init__.php
@@ -1,12 +1,13 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phutil', 'moduleutils');
+phutil_require_module('phutil', 'utils');
phutil_require_source('CelerityResourceMap.php');
diff --git a/src/infratructure/celerity/response/CelerityStaticResourceResponse.php b/src/infrastructure/celerity/response/CelerityStaticResourceResponse.php
similarity index 100%
rename from src/infratructure/celerity/response/CelerityStaticResourceResponse.php
rename to src/infrastructure/celerity/response/CelerityStaticResourceResponse.php
diff --git a/src/infratructure/celerity/response/__init__.php b/src/infrastructure/celerity/response/__init__.php
similarity index 75%
rename from src/infratructure/celerity/response/__init__.php
rename to src/infrastructure/celerity/response/__init__.php
index f6c34a4047..443a0c6c64 100644
--- a/src/infratructure/celerity/response/__init__.php
+++ b/src/infrastructure/celerity/response/__init__.php
@@ -1,14 +1,14 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/map');
+phutil_require_module('phabricator', 'infrastructure/celerity/map');
phutil_require_module('phutil', 'markup');
phutil_require_source('CelerityStaticResourceResponse.php');
diff --git a/src/infratructure/javelin/api/Javelin.php b/src/infrastructure/env/PhabricatorEnv.php
similarity index 62%
copy from src/infratructure/javelin/api/Javelin.php
copy to src/infrastructure/env/PhabricatorEnv.php
index b6e2a3d9cf..5dedac9344 100644
--- a/src/infratructure/javelin/api/Javelin.php
+++ b/src/infrastructure/env/PhabricatorEnv.php
@@ -1,24 +1,34 @@
<?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.
*/
-final class Javelin {
- public static function initBehavior($behavior, array $config = array()) {
- $response = CelerityAPI::getStaticResourceResponse();
- $response->initBehavior($behavior, $config);
+final class PhabricatorEnv {
+ private static $env;
+
+ public static function setEnvConfig(array $config) {
+ self::$env = $config;
+ }
+
+ public static function getEnvConfig($key, $default = null) {
+ return idx(self::$env, $key, $default);
}
+
+ public static function getURI($path) {
+ return rtrim(self::getEnvConfig('phabricator.base-uri'), '/').$path;
+ }
+
}
diff --git a/src/infratructure/celerity/map/__init__.php b/src/infrastructure/env/__init__.php
similarity index 51%
rename from src/infratructure/celerity/map/__init__.php
rename to src/infrastructure/env/__init__.php
index e2362e7274..ca8608ef16 100644
--- a/src/infratructure/celerity/map/__init__.php
+++ b/src/infrastructure/env/__init__.php
@@ -1,12 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phutil', 'moduleutils');
+phutil_require_module('phutil', 'utils');
-phutil_require_source('CelerityResourceMap.php');
+phutil_require_source('PhabricatorEnv.php');
diff --git a/src/infratructure/javelin/api/Javelin.php b/src/infrastructure/javelin/api/Javelin.php
similarity index 100%
copy from src/infratructure/javelin/api/Javelin.php
copy to src/infrastructure/javelin/api/Javelin.php
diff --git a/src/infratructure/javelin/api/__init__.php b/src/infrastructure/javelin/api/__init__.php
similarity index 67%
rename from src/infratructure/javelin/api/__init__.php
rename to src/infrastructure/javelin/api/__init__.php
index 59283cfb85..697729da64 100644
--- a/src/infratructure/javelin/api/__init__.php
+++ b/src/infrastructure/javelin/api/__init__.php
@@ -1,12 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_source('Javelin.php');
diff --git a/src/infratructure/javelin/markup/__init__.php b/src/infrastructure/javelin/markup/__init__.php
similarity index 73%
rename from src/infratructure/javelin/markup/__init__.php
rename to src/infrastructure/javelin/markup/__init__.php
index c8a31bd6b6..790f5404cc 100644
--- a/src/infratructure/javelin/markup/__init__.php
+++ b/src/infrastructure/javelin/markup/__init__.php
@@ -1,14 +1,14 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phutil', 'markup');
phutil_require_source('markup.php');
diff --git a/src/infratructure/javelin/markup/markup.php b/src/infrastructure/javelin/markup/markup.php
similarity index 100%
rename from src/infratructure/javelin/markup/markup.php
rename to src/infrastructure/javelin/markup/markup.php
diff --git a/src/view/control/table/__init__.php b/src/view/control/table/__init__.php
index b7edc7e84a..c739a74a41 100644
--- a/src/view/control/table/__init__.php
+++ b/src/view/control/table/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'utils');
phutil_require_source('AphrontTableView.php');
diff --git a/src/view/dialog/__init__.php b/src/view/dialog/__init__.php
index f01e8af4d8..8524dfbb6f 100644
--- a/src/view/dialog/__init__.php
+++ b/src/view/dialog/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('AphrontDialogView.php');
diff --git a/src/view/form/base/__init__.php b/src/view/form/base/__init__.php
index a5fe0834f2..981c2408dd 100644
--- a/src/view/form/base/__init__.php
+++ b/src/view/form/base/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('AphrontFormView.php');
diff --git a/src/view/form/control/base/AphrontFormControl.php b/src/view/form/control/base/AphrontFormControl.php
index b5c93fd814..b35988d64b 100755
--- a/src/view/form/control/base/AphrontFormControl.php
+++ b/src/view/form/control/base/AphrontFormControl.php
@@ -1,137 +1,145 @@
<?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.
*/
abstract class AphrontFormControl extends AphrontView {
private $label;
private $caption;
private $error;
private $name;
private $value;
private $disabled;
public function setLabel($label) {
$this->label = $label;
return $this;
}
public function getLabel() {
return $this->label;
}
public function setCaption($caption) {
$this->caption = $caption;
return $this;
}
public function getCaption() {
return $this->caption;
}
public function setError($error) {
$this->error = $error;
return $this;
}
public function getError() {
return $this->error;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
public function setValue($value) {
$this->value = $value;
return $this;
}
public function getValue() {
return $this->value;
}
public function setDisabled($disabled) {
$this->disabled = $disabled;
return $this;
}
public function getDisabled() {
return $this->disabled;
}
abstract protected function renderInput();
abstract protected function getCustomControlClass();
+ protected function shouldRender() {
+ return true;
+ }
+
final public function render() {
+ if (!$this->shouldRender()) {
+ return null;
+ }
+
$custom_class = $this->getCustomControlClass();
if (strlen($this->getLabel())) {
$label =
'<label class="aphront-form-label">'.
phutil_escape_html($this->getLabel()).
':'.
'</label>';
} else {
$label = null;
$custom_class .= ' aphront-form-control-nolabel';
}
$input =
'<div class="aphront-form-input">'.
$this->renderInput().
'</div>';
if (strlen($this->getError())) {
$error = $this->getError();
if ($error === true) {
$error = '*';
} else {
$error = "\xC2\xAB ".$error;
}
$error =
'<div class="aphront-form-error">'.
phutil_escape_html($error).
'</div>';
} else {
$error = null;
}
if (strlen($this->getCaption())) {
$caption =
'<div class="aphront-form-caption">'.
- phutil_escape_html($this->getCaption()).
+ $this->getCaption().
'</div>';
} else {
$caption = null;
}
return
'<div class="aphront-form-control '.$custom_class.'">'.
$error.
$label.
$input.
$caption.
'<div style="clear: both;"></div>'.
'</div>';
}
}
diff --git a/src/view/form/control/checkbox/__init__.php b/src/view/form/control/checkbox/__init__.php
index 612300678f..9194f048d6 100644
--- a/src/view/form/control/checkbox/__init__.php
+++ b/src/view/form/control/checkbox/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/form/control/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('AphrontFormCheckboxControl.php');
diff --git a/src/infratructure/javelin/api/Javelin.php b/src/view/form/control/password/AphrontFormPasswordControl.php
old mode 100644
new mode 100755
similarity index 57%
rename from src/infratructure/javelin/api/Javelin.php
rename to src/view/form/control/password/AphrontFormPasswordControl.php
index b6e2a3d9cf..cb0f259fbb
--- a/src/infratructure/javelin/api/Javelin.php
+++ b/src/view/form/control/password/AphrontFormPasswordControl.php
@@ -1,24 +1,36 @@
<?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.
*/
-final class Javelin {
- public static function initBehavior($behavior, array $config = array()) {
- $response = CelerityAPI::getStaticResourceResponse();
- $response->initBehavior($behavior, $config);
+class AphrontFormPasswordControl extends AphrontFormControl {
+
+ protected function getCustomControlClass() {
+ return 'aphront-form-control-password';
+ }
+
+ protected function renderInput() {
+ return phutil_render_tag(
+ 'input',
+ array(
+ 'type' => 'password',
+ 'name' => $this->getName(),
+ 'value' => $this->getValue(),
+ 'disabled' => $this->getDisabled() ? 'disabled' : null,
+ ));
}
+
}
diff --git a/src/view/form/control/checkbox/__init__.php b/src/view/form/control/password/__init__.php
similarity index 63%
copy from src/view/form/control/checkbox/__init__.php
copy to src/view/form/control/password/__init__.php
index 612300678f..42c6af6b7b 100644
--- a/src/view/form/control/checkbox/__init__.php
+++ b/src/view/form/control/password/__init__.php
@@ -1,15 +1,14 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
phutil_require_module('phabricator', 'view/form/control/base');
phutil_require_module('phutil', 'markup');
-phutil_require_source('AphrontFormCheckboxControl.php');
+phutil_require_source('AphrontFormPasswordControl.php');
diff --git a/src/view/form/control/recaptcha/AphrontFormRecaptchaControl.php b/src/view/form/control/recaptcha/AphrontFormRecaptchaControl.php
new file mode 100755
index 0000000000..a3def8c0f5
--- /dev/null
+++ b/src/view/form/control/recaptcha/AphrontFormRecaptchaControl.php
@@ -0,0 +1,65 @@
+<?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.
+ */
+
+class AphrontFormRecaptchaControl extends AphrontFormControl {
+
+ protected function getCustomControlClass() {
+ return 'aphront-form-control-recaptcha';
+ }
+
+ protected function shouldRender() {
+ return self::isRecaptchaEnabled();
+ }
+
+ private static function isRecaptchaEnabled() {
+ return PhabricatorEnv::getEnvConfig('recaptcha.enabled');
+ }
+
+ private static function requireLib() {
+ $root = phutil_get_library_root('phabricator');
+ require_once dirname($root).'/externals/recaptcha/recaptchalib.php';
+ }
+
+ public static function processCaptcha(AphrontRequest $request) {
+ if (!self::isRecaptchaEnabled()) {
+ return true;
+ }
+
+ self::requireLib();
+
+ $challenge = $request->getStr('recaptcha_challenge_field');
+ $response = $request->getStr('recaptcha_response_field');
+ $resp = recaptcha_check_answer(
+ PhabricatorEnv::getEnvConfig('recaptcha.private-key'),
+ $_SERVER['REMOTE_ADDR'],
+ $challenge,
+ $response);
+
+ return (bool)@$resp->is_valid;
+ }
+
+ protected function renderInput() {
+ self::requireLib();
+
+ return recaptcha_get_html(
+ PhabricatorEnv::getEnvConfig('recaptcha.public-key'),
+ $error = null,
+ $use_ssl = false);
+ }
+
+}
diff --git a/src/view/form/control/checkbox/__init__.php b/src/view/form/control/recaptcha/__init__.php
similarity index 50%
copy from src/view/form/control/checkbox/__init__.php
copy to src/view/form/control/recaptcha/__init__.php
index 612300678f..3803deffe0 100644
--- a/src/view/form/control/checkbox/__init__.php
+++ b/src/view/form/control/recaptcha/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/form/control/base');
-phutil_require_module('phutil', 'markup');
+phutil_require_module('phutil', 'moduleutils');
-phutil_require_source('AphrontFormCheckboxControl.php');
+phutil_require_source('AphrontFormRecaptchaControl.php');
diff --git a/src/view/form/control/tokenizer/__init__.php b/src/view/form/control/tokenizer/__init__.php
index 85ffaeed29..cafca95676 100644
--- a/src/view/form/control/tokenizer/__init__.php
+++ b/src/view/form/control/tokenizer/__init__.php
@@ -1,18 +1,18 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
-phutil_require_module('phabricator', 'infratructure/javelin/api');
-phutil_require_module('phabricator', 'infratructure/javelin/markup');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/javelin/api');
+phutil_require_module('phabricator', 'infrastructure/javelin/markup');
phutil_require_module('phabricator', 'view/form/control/base');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('AphrontFormTokenizerControl.php');
diff --git a/src/view/layout/panel/__init__.php b/src/view/layout/panel/__init__.php
index b785c8826c..ecbbacbce0 100644
--- a/src/view/layout/panel/__init__.php
+++ b/src/view/layout/panel/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('AphrontPanelView.php');
diff --git a/src/view/layout/sidenav/__init__.php b/src/view/layout/sidenav/__init__.php
index cc651dfe31..8900ccaaae 100644
--- a/src/view/layout/sidenav/__init__.php
+++ b/src/view/layout/sidenav/__init__.php
@@ -1,14 +1,14 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phabricator', 'view/null');
phutil_require_source('AphrontSideNavView.php');
diff --git a/src/view/page/failure/__init__.php b/src/view/page/failure/__init__.php
index 2129a18212..130c08b9eb 100644
--- a/src/view/page/failure/__init__.php
+++ b/src/view/page/failure/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phutil', 'markup');
phutil_require_source('AphrontRequestFailureView.php');
diff --git a/src/view/page/standard/__init__.php b/src/view/page/standard/__init__.php
index 2d2bef01bd..0c3b7c5719 100644
--- a/src/view/page/standard/__init__.php
+++ b/src/view/page/standard/__init__.php
@@ -1,16 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'infratructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/page/base');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorStandardPageView.php');
diff --git a/webroot/index.php b/webroot/index.php
index 006c8538cb..8451c8aa78 100644
--- a/webroot/index.php
+++ b/webroot/index.php
@@ -1,98 +1,125 @@
<?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.
*/
+$env = getenv('PHABRICATOR_ENV');
+if (!$env) {
+ header('Content-Type: text/plain');
+ die(
+ "CONFIG ERROR: ".
+ "The 'PHABRICATOR_ENV' environmental variable is not defined. Modify ".
+ "your httpd.conf to include 'SetEnv PHABRICATOR_ENV <env>', where '<env>' ".
+ "is one of 'development', 'production', or a custom environment.");
+}
+
+$conf = phabricator_read_config_file($env);
+$conf['phabricator.env'] = $env;
+
setup_aphront_basics();
+phutil_require_module('phabricator', 'infrastructure/env');
+PhabricatorEnv::setEnvConfig($conf);
+
$host = $_SERVER['HTTP_HOST'];
$path = $_REQUEST['__path__'];
// Based on the host and path, choose which application should serve the
// request. The default is the Aphront demo, but you'll want to replace this
// with whichever other applications you're running.
switch ($host) {
default:
phutil_require_module('phutil', 'autoload');
phutil_autoload_class('AphrontDefaultApplicationConfiguration');
$application = new AphrontDefaultApplicationConfiguration();
break;
}
$application->setHost($host);
$application->setPath($path);
$request = $application->buildRequest();
$application->setRequest($request);
list($controller, $uri_data) = $application->buildController();
try {
$controller->willBeginExecution();
$controller->willProcessRequest($uri_data);
$response = $controller->processRequest();
} catch (AphrontRedirectException $ex) {
$response = id(new AphrontRedirectResponse())
->setURI($ex->getURI());
} catch (Exception $ex) {
$response = $application->handleException($ex);
}
$response = $application->willSendResponse($response);
$response->setRequest($request);
$response_string = $response->buildResponseString();
$code = $response->getHTTPResponseCode();
if ($code != 200) {
header("HTTP/1.0 {$code}");
}
$headers = $response->getCacheHeaders();
$headers = array_merge($headers, $response->getHeaders());
foreach ($headers as $header) {
list($header, $value) = $header;
header("{$header}: {$value}");
}
echo $response_string;
/**
* @group aphront
*/
function setup_aphront_basics() {
$aphront_root = dirname(dirname(__FILE__));
$libraries_root = dirname($aphront_root);
ini_set('include_path', ini_get('include_path').':'.$libraries_root.'/');
@include_once 'libphutil/src/__phutil_library_init__.php';
if (!@constant('__LIBPHUTIL__')) {
echo "ERROR: Unable to load libphutil. Update your PHP 'include_path' to ".
"include the parent directory of libphutil/.\n";
exit(1);
}
if (!ini_get('date.timezone')) {
date_default_timezone_set('America/Los_Angeles');
}
phutil_load_library($libraries_root.'/arcanist/src');
phutil_load_library($aphront_root.'/src');
}
function __autoload($class_name) {
PhutilSymbolLoader::loadClass($class_name);
}
+
+
+function phabricator_read_config_file($config) {
+ $root = dirname(dirname(__FILE__));
+ $conf = include $root.'/conf/'.$config.'.conf.php';
+ if ($conf === false) {
+ throw new Exception("Failed to read config file '{$config}'.");
+ }
+ return $conf;
+}
+
diff --git a/webroot/rsrc/css/aphront/panel-view.css b/webroot/rsrc/css/aphront/panel-view.css
index 1acd2f7560..1aaed03fa4 100644
--- a/webroot/rsrc/css/aphront/panel-view.css
+++ b/webroot/rsrc/css/aphront/panel-view.css
@@ -1,40 +1,39 @@
/**
* @provides aphront-panel-view-css
*/
.aphront-panel-view {
background: #f3f3f3;
border: 1px solid #c0c0c0;
border-width: 1px 0 0;
padding: 1em 2em;
margin: 1em 2em;
}
.aphront-panel-view h1 {
font-size: 14px;
font-weight: bold;
padding: 2px 0 8px;
}
.aphront-panel-view a.create-button {
float: right;
}
.aphront-panel-view p.aphront-panel-instructions {
margin: .5em 2em .75em;
font-size: 13px;
}
.aphront-panel-width-form {
width: 720px;
margin-right: auto;
margin-left: auto;
}
.aphront-panel-width-wide {
width: 1080px;
margin-right: auto;
margin-left: auto;
}
-
diff --git a/webroot/rsrc/css/aphront/request-failure-view.css b/webroot/rsrc/css/aphront/request-failure-view.css
index de13f0a6a0..5d76af5123 100644
--- a/webroot/rsrc/css/aphront/request-failure-view.css
+++ b/webroot/rsrc/css/aphront/request-failure-view.css
@@ -1,27 +1,41 @@
/**
* @provides aphront-request-failure-view-css
*/
.aphront-request-failure-view {
margin: 2em auto;
background: #eff2f7;
width: 600px;
}
.aphront-request-failure-view .aphront-request-failure-head {
padding: 1em 2em;
border-bottom: 1px solid #afb2b7;
background: #dfe2e7;
}
.aphront-request-failure-view .aphront-request-failure-head h1 {
font-size: 24px;
}
.aphront-request-failure-view .aphront-request-failure-body {
- padding: 1em 2em;
+ padding: 1em 2em 1.5em;
}
.aphront-request-failure-view .aphront-request-failure-body p {
- margin: .5em 0 1.25em;
+ margin: .5em 0;
+}
+
+.aphront-failure-continue {
+ margin-top: 1.5em;
+ text-align: right;
+}
+
+.aphront-failure-continue a.button {
+ margin-left: 1em;
+}
+
+.aphront-request-failure-view ul {
+ list-style: disc;
+ margin-left: 3em;
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 1, 1:33 PM (2 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
163710
Default Alt Text
(136 KB)

Event Timeline