Example #1
0
 /**
  * Searches for purchased items in the WoltLab Plugin-Store.
  * 
  * @return	array<string>
  */
 public function searchForPurchasedItems()
 {
     if (!RemoteFile::supportsSSL()) {
         return array('noSSL' => WCF::getLanguage()->get('wcf.acp.pluginStore.api.noSSL'));
     }
     if (empty($this->parameters['username']) || empty($this->parameters['password'])) {
         return array('template' => $this->renderAuthorizationDialog(false));
     }
     $request = new HTTPRequest('https://api.woltlab.com/1.0/customer/purchases/list.json', array('method' => 'POST'), array('username' => $this->parameters['username'], 'password' => $this->parameters['password'], 'wcfVersion' => WCF_VERSION));
     $request->execute();
     $reply = $request->getReply();
     $response = JSON::decode($reply['body']);
     $code = isset($response['status']) ? $response['status'] : 500;
     switch ($code) {
         case 200:
             if (empty($response['products'])) {
                 return array('noResults' => WCF::getLanguage()->get('wcf.acp.pluginStore.purchasedItems.noResults'));
             } else {
                 WCF::getSession()->register('__pluginStoreProducts', $response['products']);
                 WCF::getSession()->register('__pluginStoreWcfMajorReleases', $response['wcfMajorReleases']);
                 return array('redirectURL' => LinkHandler::getInstance()->getLink('PluginStorePurchasedItems'));
             }
             break;
             // authentication error
         // authentication error
         case 401:
             return array('template' => $this->renderAuthorizationDialog(true));
             break;
             // any other kind of errors
         // any other kind of errors
         default:
             throw new SystemException(WCF::getLanguage()->getDynamicVariable('wcf.acp.pluginStore.api.error', array('status' => $code)));
             break;
     }
 }
 /**
  * Validates response.
  * 
  * @param	string		$response
  */
 public function validate($response)
 {
     // fail if response is empty to avoid sending api requests
     if (empty($response)) {
         throw new UserInputException('recaptchaString', 'false');
     }
     $request = new HTTPRequest('https://www.google.com/recaptcha/api/siteverify?secret=' . rawurlencode(RECAPTCHA_PRIVATEKEY) . '&response=' . rawurlencode($response) . '&remoteip=' . rawurlencode(UserUtil::getIpAddress()), array('timeout' => 10));
     try {
         $request->execute();
         $reply = $request->getReply();
         $data = JSON::decode($reply['body']);
         if ($data['success']) {
             // yeah
         } else {
             throw new UserInputException('recaptchaString', 'false');
         }
     } catch (SystemException $e) {
         // log error, but accept captcha
         $e->getExceptionID();
     }
     WCF::getSession()->register('recaptchaDone', true);
 }
Example #3
0
 /**
  * @see	\wcf\action\IAction::execute()
  */
 public function execute()
 {
     parent::execute();
     // user accepted the connection
     if (isset($_GET['code'])) {
         try {
             // fetch access_token
             $request = new HTTPRequest('https://github.com/login/oauth/access_token', array(), array('client_id' => StringUtil::trim(GITHUB_PUBLIC_KEY), 'client_secret' => StringUtil::trim(GITHUB_PRIVATE_KEY), 'code' => $_GET['code']));
             $request->execute();
             $reply = $request->getReply();
             $content = $reply['body'];
         } catch (SystemException $e) {
             // force logging
             $e->getExceptionID();
             throw new IllegalLinkException();
         }
         // validate state, validation of state is executed after fetching the access_token to invalidate 'code'
         if (!isset($_GET['state']) || $_GET['state'] != WCF::getSession()->getVar('__githubInit')) {
             throw new IllegalLinkException();
         }
         WCF::getSession()->unregister('__githubInit');
         parse_str($content, $data);
         // check whether the token is okay
         if (isset($data['error'])) {
             throw new IllegalLinkException();
         }
         // check whether a user is connected to this github account
         $user = $this->getUser($data['access_token']);
         if ($user->userID) {
             // a user is already connected, but we are logged in, break
             if (WCF::getUser()->userID) {
                 throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.github.connect.error.inuse'));
             } else {
                 if (UserAuthenticationFactory::getInstance()->getUserAuthentication()->supportsPersistentLogins()) {
                     $password = StringUtil::getRandomID();
                     $userEditor = new UserEditor($user);
                     $userEditor->update(array('password' => $password));
                     // reload user to retrieve salt
                     $user = new User($user->userID);
                     UserAuthenticationFactory::getInstance()->getUserAuthentication()->storeAccessData($user, $user->username, $password);
                 }
                 WCF::getSession()->changeUser($user);
                 WCF::getSession()->update();
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink());
             }
         } else {
             try {
                 // fetch userdata
                 $request = new HTTPRequest('https://api.github.com/user?access_token=' . $data['access_token']);
                 $request->execute();
                 $reply = $request->getReply();
                 $userData = JSON::decode(StringUtil::trim($reply['body']));
             } catch (SystemException $e) {
                 // force logging
                 $e->getExceptionID();
                 throw new IllegalLinkException();
             }
             WCF::getSession()->register('__3rdPartyProvider', 'github');
             // save data for connection
             if (WCF::getUser()->userID) {
                 WCF::getSession()->register('__githubUsername', $userData['login']);
                 WCF::getSession()->register('__githubToken', $data['access_token']);
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink('AccountManagement') . '#3rdParty');
             } else {
                 WCF::getSession()->register('__githubData', $userData);
                 WCF::getSession()->register('__username', $userData['login']);
                 // check whether user has entered a public email
                 if (isset($userData) && isset($userData['email']) && $userData['email'] !== null) {
                     WCF::getSession()->register('__email', $userData['email']);
                 } else {
                     try {
                         $request = new HTTPRequest('https://api.github.com/user/emails?access_token=' . $data['access_token']);
                         $request->execute();
                         $reply = $request->getReply();
                         $emails = JSON::decode(StringUtil::trim($reply['body']));
                         // handle future response as well a current response (see. http://developer.github.com/v3/users/emails/)
                         if (is_string($emails[0])) {
                             $email = $emails[0];
                         } else {
                             $email = $emails[0]['email'];
                             foreach ($emails as $tmp) {
                                 if ($tmp['primary']) {
                                     $email = $tmp['email'];
                                 }
                                 break;
                             }
                         }
                         WCF::getSession()->register('__email', $email);
                     } catch (SystemException $e) {
                     }
                 }
                 WCF::getSession()->register('__githubToken', $data['access_token']);
                 // we assume that bots won't register on github first
                 // thus no need for a captcha
                 if (REGISTER_USE_CAPTCHA) {
                     WCF::getSession()->register('noRegistrationCaptcha', true);
                 }
                 WCF::getSession()->update();
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Register'));
             }
         }
         $this->executed();
         exit;
     }
     // user declined or any other error that may occur
     if (isset($_GET['error'])) {
         throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.github.login.error.' . $_GET['error']));
     }
     // start auth by redirecting to github
     $token = StringUtil::getRandomID();
     WCF::getSession()->register('__githubInit', $token);
     HeaderUtil::redirect("https://github.com/login/oauth/authorize?client_id=" . rawurlencode(StringUtil::trim(GITHUB_PUBLIC_KEY)) . "&scope=" . rawurlencode('user:email') . "&state=" . $token);
     $this->executed();
     exit;
 }
 /**
  * @see	\wcf\action\IAction::execute()
  */
 public function execute()
 {
     parent::execute();
     $callbackURL = LinkHandler::getInstance()->getLink('FacebookAuth');
     // Work around Facebook performing an illegal substitution of the Slash
     // by '%2F' when entering redirect URI (RFC 3986 sect. 2.2, sect. 3.4)
     $callbackURL = preg_replace_callback('/(?<=\\?).*/', function ($matches) {
         return rawurlencode($matches[0]);
     }, $callbackURL);
     // user accepted the connection
     if (isset($_GET['code'])) {
         try {
             // fetch access_token
             $request = new HTTPRequest('https://graph.facebook.com/oauth/access_token?client_id=' . StringUtil::trim(FACEBOOK_PUBLIC_KEY) . '&redirect_uri=' . rawurlencode($callbackURL) . '&client_secret=' . StringUtil::trim(FACEBOOK_PRIVATE_KEY) . '&code=' . rawurlencode($_GET['code']));
             $request->execute();
             $reply = $request->getReply();
             $content = $reply['body'];
         } catch (SystemException $e) {
             // force logging
             $e->getExceptionID();
             throw new IllegalLinkException();
         }
         // validate state, validation of state is executed after fetching the access_token to invalidate 'code'
         if (!isset($_GET['state']) || $_GET['state'] != WCF::getSession()->getVar('__facebookInit')) {
             throw new IllegalLinkException();
         }
         WCF::getSession()->unregister('__facebookInit');
         parse_str($content, $data);
         try {
             // fetch userdata
             $request = new HTTPRequest('https://graph.facebook.com/me?access_token=' . rawurlencode($data['access_token']) . '&fields=birthday,bio,email,gender,id,location,name,picture.type(large),website');
             $request->execute();
             $reply = $request->getReply();
             $content = $reply['body'];
         } catch (SystemException $e) {
             // force logging
             $e->getExceptionID();
             throw new IllegalLinkException();
         }
         $userData = JSON::decode($content);
         // check whether a user is connected to this facebook account
         $user = $this->getUser($userData['id']);
         if ($user->userID) {
             // a user is already connected, but we are logged in, break
             if (WCF::getUser()->userID) {
                 throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.facebook.connect.error.inuse'));
             } else {
                 if (UserAuthenticationFactory::getInstance()->getUserAuthentication()->supportsPersistentLogins()) {
                     $password = StringUtil::getRandomID();
                     $userEditor = new UserEditor($user);
                     $userEditor->update(array('password' => $password));
                     // reload user to retrieve salt
                     $user = new User($user->userID);
                     UserAuthenticationFactory::getInstance()->getUserAuthentication()->storeAccessData($user, $user->username, $password);
                 }
                 WCF::getSession()->changeUser($user);
                 WCF::getSession()->update();
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink());
             }
         } else {
             WCF::getSession()->register('__3rdPartyProvider', 'facebook');
             // save data for connection
             if (WCF::getUser()->userID) {
                 WCF::getSession()->register('__facebookUsername', $userData['name']);
                 WCF::getSession()->register('__facebookData', $userData);
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink('AccountManagement') . '#3rdParty');
             } else {
                 WCF::getSession()->register('__username', $userData['name']);
                 if (isset($userData['email'])) {
                     WCF::getSession()->register('__email', $userData['email']);
                 }
                 WCF::getSession()->register('__facebookData', $userData);
                 // we assume that bots won't register on facebook first
                 // thus no need for a captcha
                 if (REGISTER_USE_CAPTCHA) {
                     WCF::getSession()->register('noRegistrationCaptcha', true);
                 }
                 WCF::getSession()->update();
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Register'));
             }
         }
         $this->executed();
         exit;
     }
     // user declined or any other error that may occur
     if (isset($_GET['error'])) {
         throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.facebook.login.error.' . $_GET['error']));
     }
     // start auth by redirecting to facebook
     $token = StringUtil::getRandomID();
     WCF::getSession()->register('__facebookInit', $token);
     HeaderUtil::redirect("https://www.facebook.com/dialog/oauth?client_id=" . StringUtil::trim(FACEBOOK_PUBLIC_KEY) . "&redirect_uri=" . rawurlencode($callbackURL) . "&state=" . $token . "&scope=email,user_about_me,user_birthday,user_location,user_website");
     $this->executed();
     exit;
 }
    /**
     * @see	\wcf\page\IPage::readData()
     */
    public function readData()
    {
        AbstractPage::readData();
        $fileNameRegex = new Regex('(?:^|/)\\d{4}-\\d{2}-\\d{2}\\.txt$');
        $this->logFiles = DirectoryUtil::getInstance(WCF_DIR . 'log/')->getFiles(SORT_DESC, $fileNameRegex);
        if ($this->exceptionID) {
            // search the appropriate file
            foreach ($this->logFiles as $logFile) {
                $contents = file_get_contents($logFile);
                if (mb_strpos($contents, '<<<<<<<<' . $this->exceptionID . '<<<<') !== false) {
                    $fileNameRegex->match($logFile);
                    $matches = $fileNameRegex->getMatches();
                    $this->logFile = $matches[0];
                    break;
                }
                unset($contents);
            }
            if (!isset($contents)) {
                $this->logFile = '';
                return;
            }
        } else {
            if ($this->logFile) {
                if (!$fileNameRegex->match(basename($this->logFile))) {
                    throw new IllegalLinkException();
                }
                if (!file_exists(WCF_DIR . 'log/' . $this->logFile)) {
                    throw new IllegalLinkException();
                }
                $contents = file_get_contents(WCF_DIR . 'log/' . $this->logFile);
            } else {
                return;
            }
        }
        // unify newlines
        $contents = StringUtil::unifyNewlines($contents);
        // split contents
        $split = new Regex('(?:^|\\n<<<<\\n\\n)(?:<<<<<<<<([a-f0-9]{40})<<<<\\n|$)');
        $contents = $split->split($contents, Regex::SPLIT_NON_EMPTY_ONLY | Regex::CAPTURE_SPLIT_DELIMITER);
        // even items become keys, odd items become values
        try {
            $this->exceptions = call_user_func_array('array_merge', array_map(function ($v) {
                return array($v[0] => $v[1]);
            }, array_chunk($contents, 2)));
        } catch (\Exception $e) {
            // logfile contents are pretty malformed, abort
            return;
        }
        if ($this->exceptionID) {
            $this->searchPage($this->exceptionID);
        }
        $this->calculateNumberOfPages();
        $i = 0;
        $exceptionRegex = new Regex('(?P<date>[MTWFS][a-z]{2}, \\d{1,2} [JFMASOND][a-z]{2} \\d{4} \\d{2}:\\d{2}:\\d{2} [+-]\\d{4})
Message: (?P<message>.*?)
File: (?P<file>.*?) \\((?P<line>\\d+)\\)
PHP version: (?P<phpVersion>.*?)
WCF version: (?P<wcfVersion>.*?)
Request URI: (?P<requestURI>.*?)
Referrer: (?P<referrer>.*?)
User-Agent: (?P<userAgent>.*?)
Information: (?P<information>.*?)
Stacktrace: 
(?P<stacktrace>.*)', Regex::DOT_ALL);
        $stackTraceFormatter = new Regex('^\\s+(#\\d+)', Regex::MULTILINE);
        foreach ($this->exceptions as $key => $val) {
            $i++;
            if ($i < $this->startIndex || $i > $this->endIndex) {
                unset($this->exceptions[$key]);
                continue;
            }
            if (!$exceptionRegex->match($val)) {
                unset($this->exceptions[$key]);
                continue;
            }
            $this->exceptions[$key] = $exceptionRegex->getMatches();
            $this->exceptions[$key]['stacktrace'] = explode("\n", $stackTraceFormatter->replace(StringUtil::encodeHTML($this->exceptions[$key]['stacktrace']), '<strong>\\1</strong>'));
            $this->exceptions[$key]['information'] = JSON::decode($this->exceptions[$key]['information']);
        }
    }
 /**
  * @see	\wcf\action\IAction::execute()
  */
 public function execute()
 {
     parent::execute();
     $callbackURL = LinkHandler::getInstance()->getLink('GoogleAuth', array('appendSession' => false));
     // user accepted the connection
     if (isset($_GET['code'])) {
         try {
             // fetch access_token
             $request = new HTTPRequest('https://accounts.google.com/o/oauth2/token', array(), array('code' => $_GET['code'], 'client_id' => StringUtil::trim(GOOGLE_PUBLIC_KEY), 'client_secret' => StringUtil::trim(GOOGLE_PRIVATE_KEY), 'redirect_uri' => $callbackURL, 'grant_type' => 'authorization_code'));
             $request->execute();
             $reply = $request->getReply();
             $content = $reply['body'];
         } catch (SystemException $e) {
             // force logging
             $e->getExceptionID();
             throw new IllegalLinkException();
         }
         // validate state, validation of state is executed after fetching the access_token to invalidate 'code'
         if (!isset($_GET['state']) || $_GET['state'] != WCF::getSession()->getVar('__googleInit')) {
             throw new IllegalLinkException();
         }
         WCF::getSession()->unregister('__googleInit');
         $data = JSON::decode($content);
         try {
             // fetch userdata
             $request = new HTTPRequest('https://www.googleapis.com/plus/v1/people/me');
             $request->addHeader('Authorization', 'Bearer ' . $data['access_token']);
             $request->execute();
             $reply = $request->getReply();
             $content = $reply['body'];
         } catch (SystemException $e) {
             // force logging
             $e->getExceptionID();
             throw new IllegalLinkException();
         }
         $userData = JSON::decode($content);
         // check whether a user is connected to this google account
         $user = $this->getUser($userData['id']);
         if ($user->userID) {
             // a user is already connected, but we are logged in, break
             if (WCF::getUser()->userID) {
                 throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.google.connect.error.inuse'));
             } else {
                 if (UserAuthenticationFactory::getInstance()->getUserAuthentication()->supportsPersistentLogins()) {
                     $password = StringUtil::getRandomID();
                     $userEditor = new UserEditor($user);
                     $userEditor->update(array('password' => $password));
                     // reload user to retrieve salt
                     $user = new User($user->userID);
                     UserAuthenticationFactory::getInstance()->getUserAuthentication()->storeAccessData($user, $user->username, $password);
                 }
                 WCF::getSession()->changeUser($user);
                 WCF::getSession()->update();
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink());
             }
         } else {
             WCF::getSession()->register('__3rdPartyProvider', 'google');
             // save data for connection
             if (WCF::getUser()->userID) {
                 WCF::getSession()->register('__googleUsername', $userData['displayName']);
                 WCF::getSession()->register('__googleData', $userData);
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink('AccountManagement') . '#3rdParty');
             } else {
                 WCF::getSession()->register('__username', $userData['displayName']);
                 if (isset($userData['emails'][0]['value'])) {
                     WCF::getSession()->register('__email', $userData['emails'][0]['value']);
                 }
                 WCF::getSession()->register('__googleData', $userData);
                 // we assume that bots won't register on google first
                 // thus no need for a captcha
                 if (REGISTER_USE_CAPTCHA) {
                     WCF::getSession()->register('noRegistrationCaptcha', true);
                 }
                 WCF::getSession()->update();
                 HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Register'));
             }
         }
         $this->executed();
         exit;
     }
     // user declined or any other error that may occur
     if (isset($_GET['error'])) {
         throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.google.login.error.' . $_GET['error']));
     }
     // start auth by redirecting to google
     $token = StringUtil::getRandomID();
     WCF::getSession()->register('__googleInit', $token);
     HeaderUtil::redirect("https://accounts.google.com/o/oauth2/auth?client_id=" . rawurlencode(StringUtil::trim(GOOGLE_PUBLIC_KEY)) . "&redirect_uri=" . rawurlencode($callbackURL) . "&state=" . $token . "&scope=profile+email&response_type=code");
     $this->executed();
     exit;
 }
 /**
  * Reads a value and validates it. If you set $allowEmpty to true, no exception will
  * be thrown if the variable evaluates to 0 (integer) or '' (string). Furthermore the
  * variable will be always created with a sane value if it does not exist.
  * 
  * @param	string		$variableName
  * @param	boolean		$allowEmpty
  * @param	string		$arrayIndex
  * @param	integer		$type
  */
 protected function readValue($variableName, $allowEmpty, $arrayIndex, $type)
 {
     if ($arrayIndex) {
         if (!isset($this->parameters[$arrayIndex])) {
             throw new SystemException("Corrupt parameters, index '" . $arrayIndex . "' is missing");
         }
         $target =& $this->parameters[$arrayIndex];
     } else {
         $target =& $this->parameters;
     }
     switch ($type) {
         case self::TYPE_INTEGER:
             if (!isset($target[$variableName])) {
                 if ($allowEmpty) {
                     $target[$variableName] = 0;
                 } else {
                     throw new UserInputException($variableName);
                 }
             } else {
                 $target[$variableName] = intval($target[$variableName]);
                 if (!$allowEmpty && !$target[$variableName]) {
                     throw new UserInputException($variableName);
                 }
             }
             break;
         case self::TYPE_STRING:
             if (!isset($target[$variableName])) {
                 if ($allowEmpty) {
                     $target[$variableName] = '';
                 } else {
                     throw new UserInputException($variableName);
                 }
             } else {
                 $target[$variableName] = StringUtil::trim($target[$variableName]);
                 if (!$allowEmpty && empty($target[$variableName])) {
                     throw new UserInputException($variableName);
                 }
             }
             break;
         case self::TYPE_BOOLEAN:
             if (!isset($target[$variableName])) {
                 if ($allowEmpty) {
                     $target[$variableName] = false;
                 } else {
                     throw new UserInputException($variableName);
                 }
             } else {
                 if (is_numeric($target[$variableName])) {
                     $target[$variableName] = (bool) $target[$variableName];
                 } else {
                     $target[$variableName] = $target[$variableName] != 'false';
                 }
             }
             break;
         case self::TYPE_JSON:
             if (!isset($target[$variableName])) {
                 if ($allowEmpty) {
                     $target[$variableName] = array();
                 } else {
                     throw new UserInputException($variableName);
                 }
             } else {
                 try {
                     $target[$variableName] = JSON::decode($target[$variableName]);
                 } catch (SystemException $e) {
                     throw new UserInputException($variableName);
                 }
                 if (!$allowEmpty && empty($target[$variableName])) {
                     throw new UserInputException($variableName);
                 }
             }
             break;
     }
 }