public function preRequest(HTTPRequest $request, Session $session, DataModel $model)
 {
     // Bootstrap session so that Session::get() accesses the right instance
     $dummyController = new Controller();
     $dummyController->setSession($session);
     $dummyController->setRequest($request);
     $dummyController->pushCurrent();
     // Block non-authenticated users from setting the stage mode
     if (!Versioned::can_choose_site_stage($request)) {
         $permissionMessage = sprintf(_t("ContentController.DRAFT_SITE_ACCESS_RESTRICTION", 'You must log in with your CMS password in order to view the draft or archived content. ' . '<a href="%s">Click here to go back to the published site.</a>'), Convert::raw2xml(Controller::join_links(Director::baseURL(), $request->getURL(), "?stage=Live")));
         // Force output since RequestFilter::preRequest doesn't support response overriding
         $response = Security::permissionFailure($dummyController, $permissionMessage);
         $session->inst_save();
         $dummyController->popCurrent();
         // Prevent output in testing
         if (class_exists('SilverStripe\\Dev\\SapphireTest', false) && SapphireTest::is_running_test()) {
             throw new HTTPResponse_Exception($response);
         }
         $response->output();
         die;
     }
     Versioned::choose_site_stage();
     $dummyController->popCurrent();
     return true;
 }
 public function index()
 {
     // Web mode
     if (!Director::is_cli()) {
         $renderer = DebugView::create();
         echo $renderer->renderHeader();
         echo $renderer->renderInfo("SilverStripe Development Tools", Director::absoluteBaseURL());
         $base = Director::baseURL();
         echo '<div class="options"><ul>';
         $evenOdd = "odd";
         foreach (self::get_links() as $action => $description) {
             echo "<li class=\"{$evenOdd}\"><a href=\"{$base}dev/{$action}\"><b>/dev/{$action}:</b>" . " {$description}</a></li>\n";
             $evenOdd = $evenOdd == "odd" ? "even" : "odd";
         }
         echo $renderer->renderFooter();
         // CLI mode
     } else {
         echo "SILVERSTRIPE DEVELOPMENT TOOLS\n--------------------------\n\n";
         echo "You can execute any of the following commands:\n\n";
         foreach (self::get_links() as $action => $description) {
             echo "  sake dev/{$action}: {$description}\n";
         }
         echo "\n\n";
     }
 }
 /**
  * Provide downloadable url
  *
  * @param string $path
  * @return string|null
  */
 public function getPublicUrl($path)
 {
     $rootPath = realpath(BASE_PATH);
     $filesPath = realpath($this->pathPrefix);
     if (stripos($filesPath, $rootPath) === 0) {
         $dir = substr($filesPath, strlen($rootPath));
         return Controller::join_links(Director::baseURL(), $dir, $path);
     }
     // File outside of webroot can't be used
     return null;
 }
 /**
  * Set a cookie
  *
  * @param string $name The name of the cookie
  * @param string $value The value for the cookie to hold
  * @param int $expiry The number of days until expiry; 0 indicates a cookie valid for the current session
  * @param string $path The path to save the cookie on (falls back to site base)
  * @param string $domain The domain to make the cookie available on
  * @param boolean $secure Can the cookie only be sent over SSL?
  * @param boolean $httpOnly Prevent the cookie being accessible by JS
  */
 public function set($name, $value, $expiry = 90, $path = null, $domain = null, $secure = false, $httpOnly = true)
 {
     //are we setting or clearing a cookie? false values are reserved for clearing cookies (see PHP manual)
     $clear = false;
     if ($value === false || $value === '' || $expiry < 0) {
         $clear = true;
         $value = false;
     }
     //expiry === 0 is a special case where we set a cookie for the current user session
     if ($expiry !== 0) {
         //don't do the maths if we are clearing
         $expiry = $clear ? -1 : DBDatetime::now()->Format('U') + 86400 * $expiry;
     }
     //set the path up
     $path = $path ? $path : Director::baseURL();
     //send the cookie
     $this->outputCookie($name, $value, $expiry, $path, $domain, $secure, $httpOnly);
     //keep our variables in check
     if ($clear) {
         unset($this->new[$name], $this->current[$name]);
     } else {
         $this->new[$name] = $this->current[$name] = $value;
     }
 }
 /**
  * Gets the combined configuration of all LeafAndMain subclasses required by the client app.
  *
  * @return array
  *
  * WARNING: Experimental API
  */
 public function getCombinedClientConfig()
 {
     $combinedClientConfig = ['sections' => []];
     $cmsClassNames = CMSMenu::get_cms_classes('SilverStripe\\Admin\\LeftAndMain', true, CMSMenu::URL_PRIORITY);
     foreach ($cmsClassNames as $className) {
         $combinedClientConfig['sections'][$className] = Injector::inst()->get($className)->getClientConfig();
     }
     // Pass in base url (absolute and relative)
     $combinedClientConfig['baseUrl'] = Director::baseURL();
     $combinedClientConfig['absoluteBaseUrl'] = Director::absoluteBaseURL();
     $combinedClientConfig['adminUrl'] = AdminRootController::admin_url();
     // Get "global" CSRF token for use in JavaScript
     $token = SecurityToken::inst();
     $combinedClientConfig[$token->getName()] = $token->getValue();
     // Set env
     $combinedClientConfig['environment'] = Director::get_environment_type();
     $combinedClientConfig['debugging'] = $this->config()->client_debugging;
     return Convert::raw2json($combinedClientConfig);
 }
 /**
  * Redirect back. Uses either the HTTP-Referer or a manually set request-variable called "BackURL".
  * This variable is needed in scenarios where HTTP-Referer is not sent (e.g when calling a page by
  * location.href in IE). If none of the two variables is available, it will redirect to the base
  * URL (see {@link Director::baseURL()}).
  *
  * @uses redirect()
  *
  * @return bool|HTTPResponse
  */
 public function redirectBack()
 {
     // Don't cache the redirect back ever
     HTTP::set_cache_age(0);
     $url = null;
     // In edge-cases, this will be called outside of a handleRequest() context; in that case,
     // redirect to the homepage - don't break into the global state at this stage because we'll
     // be calling from a test context or something else where the global state is inappropraite
     if ($this->getRequest()) {
         if ($this->getRequest()->requestVar('BackURL')) {
             $url = $this->getRequest()->requestVar('BackURL');
         } else {
             if ($this->getRequest()->isAjax() && $this->getRequest()->getHeader('X-Backurl')) {
                 $url = $this->getRequest()->getHeader('X-Backurl');
             } else {
                 if ($this->getRequest()->getHeader('Referer')) {
                     $url = $this->getRequest()->getHeader('Referer');
                 }
             }
         }
     }
     if (!$url) {
         $url = Director::baseURL();
     }
     // absolute redirection URLs not located on this site may cause phishing
     if (Director::is_site_url($url)) {
         $url = Director::absoluteURL($url, true);
         return $this->redirect($url);
     } else {
         return false;
     }
 }
    /**
     * Check if the user has permissions to run URL debug tools,
     * else redirect them to log in.
     */
    public static function require_developer_login()
    {
        if (Director::isDev()) {
            return;
        }
        if (isset($_SESSION['loggedInAs'])) {
            // We have to do some raw SQL here, because this method is called in Object::defineMethods().
            // This means we have to be careful about what objects we create, as we don't want Object::defineMethods()
            // being called again.
            // This basically calls Permission::checkMember($_SESSION['loggedInAs'], 'ADMIN');
            // @TODO - Rewrite safely using DataList::filter
            $memberID = $_SESSION['loggedInAs'];
            $permission = DB::prepared_query('
				SELECT "ID" FROM "Permission"
				INNER JOIN "Group_Members" ON "Permission"."GroupID" = "Group_Members"."GroupID"
				WHERE "Permission"."Code" = ?
				AND "Permission"."Type" = ?
				AND "Group_Members"."MemberID" = ?', array('ADMIN', Permission::GRANT_PERMISSION, $memberID))->value();
            if ($permission) {
                return;
            }
        }
        // This basically does the same as
        // Security::permissionFailure(null, "You need to login with developer access to make use of debugging tools.")
        // We have to do this because of how early this method is called in execution.
        $_SESSION['SilverStripe\\Security\\Security']['Message']['message'] = "You need to login with developer access to make use of debugging tools.";
        $_SESSION['SilverStripe\\Security\\Security']['Message']['type'] = 'warning';
        $_SESSION['BackURL'] = $_SERVER['REQUEST_URI'];
        header($_SERVER['SERVER_PROTOCOL'] . " 302 Found");
        header("Location: " . Director::baseURL() . Security::login_url());
        die;
    }
 /**
  * Get the URL of the logout page.
  *
  * To update the logout url use the "Security.logout_url" config setting.
  *
  * @return string
  */
 public static function lost_password_url()
 {
     return Controller::join_links(Director::baseURL(), self::config()->lost_password_url);
 }
 /**
  * Returns the Absolute URL of the site root, embedding the current basic-auth credentials into
  * the URL.
  *
  * @return string
  */
 public static function absoluteBaseURLWithAuth()
 {
     $login = "";
     if (isset($_SERVER['PHP_AUTH_USER'])) {
         $login = "******";
     }
     return Director::protocol() . $login . $_SERVER['HTTP_HOST'] . Director::baseURL();
 }
 public function Link($action = null)
 {
     /** @skipUpgrade */
     return Controller::join_links(Director::baseURL(), "CMSSecurity", $action);
 }
 public function inst_destroy($removeCookie = true)
 {
     if (session_id()) {
         if ($removeCookie) {
             $path = Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_path') ?: Director::baseURL();
             $domain = Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_domain');
             $secure = Config::inst()->get('SilverStripe\\Control\\Session', 'cookie_secure');
             Cookie::force_expiry(session_name(), $path, $domain, $secure, true);
         }
         session_destroy();
         // Clean up the superglobal - session_destroy does not do it.
         // http://nz1.php.net/manual/en/function.session-destroy.php
         unset($_SESSION);
         $this->data = array();
     }
 }
 public function testRedirectBackByBackUrl()
 {
     $internalRelativeUrl = Controller::join_links(Director::baseURL(), '/some-url');
     $internalAbsoluteUrl = Controller::join_links(Director::absoluteBaseURL(), '/some-url');
     $response = $this->get('ControllerTest_Controller/redirectbacktest?BackURL=' . urlencode($internalRelativeUrl));
     $this->assertEquals(302, $response->getStatusCode());
     $this->assertEquals($internalAbsoluteUrl, $response->getHeader('Location'), "Redirects on internal relative URLs");
     $internalAbsoluteUrl = Director::absoluteBaseURL() . '/some-url';
     $response = $this->get('ControllerTest_Controller/redirectbacktest?BackURL=' . urlencode($internalAbsoluteUrl));
     $this->assertEquals($internalAbsoluteUrl, $response->getHeader('Location'));
     $this->assertEquals(302, $response->getStatusCode(), "Redirects on internal absolute URLs");
     $externalAbsoluteUrl = 'http://myhost.com/some-url';
     $response = $this->get('ControllerTest_Controller/redirectbacktest?BackURL=' . urlencode($externalAbsoluteUrl));
     $this->assertEquals(200, $response->getStatusCode(), "Doesn't redirect on external URLs");
 }
 /**
  * Provide secure downloadable
  *
  * @param string $path
  * @return string|null
  */
 public function getProtectedUrl($path)
 {
     // Public URLs are handled via a request handler within /assets.
     // If assets are stored locally, then asset paths of protected files should be equivalent.
     return Controller::join_links(Director::baseURL(), ASSETS_DIR, $path);
 }
 public function testCommentedOutScriptTagIsIgnored()
 {
     $template = '<html><head></head><body><!--<script>alert("commented out");</script>-->' . '<h1>more content</h1></body></html>';
     /** @var Requirements_Backend $backend */
     $backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
     $this->setupRequirements($backend);
     $backend->setSuffixRequirements(false);
     $src = $this->getCurrentRelativePath() . '/RequirementsTest_a.js';
     $urlSrc = ControllerTest_ContainerController::join_links(Director::baseURL(), $src);
     $backend->javascript($src);
     $html = $backend->includeInHTML($template);
     $this->assertEquals('<html><head></head><body><!--<script>alert("commented out");</script>-->' . '<h1>more content</h1><script type="application/javascript" src="' . $urlSrc . '"></script></body></html>', $html);
 }
 public function testForceSSLAlternateDomain()
 {
     Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', '/');
     $_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin';
     $output = Director::forceSSL(array('/^admin/'), 'secure.mysite.com');
     $this->assertEquals($output, 'https://secure.mysite.com/admin');
 }