public function execute(AuthenticationCredentials $authCreds) { $authService = AuthenticationService::instance(); // Make sure the creds are valid if (!$authCreds->isValid()) { Application::instance()->getLogger()->error(sprintf('Error validating auth credentials %s', var_export($authCreds, true))); throw new Exception('Invalid auth credentials'); } // Account merge if (Session::set('accountMerge') === '1') { // Must be logged in to do a merge if (!Session::hasRole(UserRole::USER)) { throw new Exception('Authentication required for account merge'); } $authService->handleAuthAndMerge($authCreds); return 'redirect: /profile/authentication'; } // Follow url *notice the set, returning and clearing the var $follow = Session::set('follow'); // If the user profile doesnt exist, go to the register page if (!$authService->getUserAuthProfileExists($authCreds)) { Session::set('authSession', $authCreds); $url = '/register?code=' . urlencode($authCreds->getAuthCode()); if (!empty($follow)) { $url .= '&follow=' . urlencode($follow); } return 'redirect: ' . $url; } // User exists, handle the auth $authService->handleAuthCredentials($authCreds); if (!empty($follow) && substr($follow, 0, 1) == '/') { return 'redirect: ' . $follow; } return 'redirect: /profile'; }
/** * Expires subscritions based on their end date * * @return int the number of expired subscriptions */ public function expiredSubscriptions() { $conn = Application::instance()->getConnection(); $authenticationService = AuthenticationService::instance(); // Expire recurring subs with a 24 hour grace period $stmt = $conn->prepare('SELECT subscriptionId,userId FROM dfl_users_subscriptions WHERE recurring = 1 AND status = :status AND endDate + INTERVAL 1 HOUR <= NOW()'); $stmt->bindValue('status', SubscriptionStatus::ACTIVE, \PDO::PARAM_STR); $stmt->execute(); $subscriptions = $stmt->fetchAll(); if (!empty($subscriptions)) { foreach ($subscriptions as $sub) { $authenticationService->flagUserForUpdate($sub['userId']); $conn->update('dfl_users_subscriptions', array('status' => SubscriptionStatus::EXPIRED), array('subscriptionId' => $sub['subscriptionId'])); } } // Expire NONE recurring subs immediately $stmt = $conn->prepare('SELECT subscriptionId,userId FROM dfl_users_subscriptions WHERE (recurring = 0 OR recurring IS NULL) AND status = :status AND endDate <= NOW()'); $stmt->bindValue('status', SubscriptionStatus::ACTIVE, \PDO::PARAM_STR); $stmt->execute(); $subscriptions = $stmt->fetchAll(); if (!empty($subscriptions)) { foreach ($subscriptions as $sub) { $authenticationService->flagUserForUpdate($sub['userId']); $conn->update('dfl_users_subscriptions', array('status' => SubscriptionStatus::EXPIRED), array('subscriptionId' => $sub['subscriptionId'])); } } }
/** * @Route ("/impersonate") * @HttpMethod ({"GET"}) * * @param array $params * @throws Exception * @return string */ public function impersonate(array $params) { if (!Config::$a['allowImpersonation']) { throw new Exception('Impersonating is not allowed'); } $userId = isset($params['userId']) && !empty($params['userId']) ? $params['userId'] : ''; $username = isset($params['username']) && !empty($params['username']) ? $params['username'] : ''; if (empty($userId) && empty($username)) { throw new Exception('[username] or [userId] required'); } $authService = AuthenticationService::instance(); $userService = UserService::instance(); if (!empty($userId)) { $user = $userService->getUserById($userId); } else { if (!empty($username)) { $user = $userService->getUserByUsername($username); } } if (empty($user)) { throw new Exception('User not found. Try a different userId or username'); } $credentials = $authService->getUserCredentials($user, 'impersonating'); Session::start(); Session::updateCredentials($credentials); ChatIntegrationService::instance()->setChatSession($credentials, Session::getSessionId()); return 'redirect: /'; }
public function execute() { $log = Application::instance()->getLogger(); $authenticationService = AuthenticationService::instance(); $subscriptionService = SubscriptionsService::instance(); $users = array(); // Renew any subscription that has an active payment profile. $subscriptions = $subscriptionService->getRecurringSubscriptionsToRenew(); foreach ($subscriptions as $subscription) { try { $subType = $subscriptionService->getSubscriptionType($subscription['subscriptionType']); // Because subscriptions can be revived after months of skipped payments; // The end date may not simply be behind by the subscription frequency. $end = Date::getDateTime($subscription['endDate']); $diff = $end->diff(new \DateTime('NOW')); $end->modify('+' . (intval($diff->format('%y') * 12) + intval($diff->format('%m'))) . ' month'); // $end->modify('+' . $subType['billingFrequency'] . ' ' . strtolower($subType['billingPeriod'])); $subscriptionService->updateSubscription(array('subscriptionId' => $subscription['subscriptionId'], 'endDate' => $end->format('Y-m-d H:i:s'), 'status' => SubscriptionStatus::ACTIVE)); $this->sendResubscribeBroadcast($subscription); $users[] = $subscription['userId']; } catch (\Exception $e) { $log->critical("Could not roll over subscription", $subscription); } } // Expire subscriptions $subscriptions = $subscriptionService->getSubscriptionsToExpire(); if (!empty($subscriptions)) { foreach ($subscriptions as $subscription) { $users[] = $subscription['userId']; $subscriptionService->updateSubscription(array('subscriptionId' => $subscription['subscriptionId'], 'status' => SubscriptionStatus::EXPIRED)); } } // Update users $users = array_unique($users); foreach ($users as $id) { $authenticationService->flagUserForUpdate($id); } // Clean-up old unfinished subscriptions (where users have aborted the process) $conn = Application::instance()->getConnection(); $stmt = $conn->prepare(' DELETE FROM `dfl_users_subscriptions` WHERE `status` = :status AND `createdDate` < (NOW() - INTERVAL 24 HOUR) '); $stmt->bindValue('status', SubscriptionStatus::_NEW, \PDO::PARAM_STR); $stmt->execute(); }
/** * @param array $params * @return Response * @throws Exception */ public function authenticate(array $params) { if (!isset($params['authtoken']) || empty($params['authtoken'])) { return new Response(Http::STATUS_FORBIDDEN, 'Invalid or empty authToken'); } $authToken = ApiAuthenticationService::instance()->getAuthToken($params['authtoken']); if (empty($authToken)) { return new Response(Http::STATUS_FORBIDDEN, 'Auth token not found'); } $user = UserService::instance()->getUserById($authToken['userId']); if (empty($user)) { return new Response(Http::STATUS_FORBIDDEN, 'User not found'); } $authenticationService = AuthenticationService::instance(); $credentials = $authenticationService->getUserCredentials($user, 'API'); $response = new Response(Http::STATUS_OK, json_encode($credentials->getData())); $response->addHeader(Http::HEADER_CONTENTTYPE, MimeType::JSON); return $response; }
/** * Checks the users current session status * Does a remember me login * @return void */ public function init() { $app = Application::instance(); $authService = AuthenticationService::instance(); // If the session hasnt started, or the data is not valid (result from php clearing the session data), check the Remember me cookie if (!Session::isStarted() || !Session::getCredentials()->isValid()) { $userId = $authService->getRememberMe(); if ($userId !== false) { $userManager = UserService::instance(); $user = $userManager->getUserById($userId); if (!empty($user)) { Session::start(Session::START_NOCOOKIE); $credentials = $authService->getUserCredentials($user, 'rememberme'); Session::updateCredentials($credentials); ChatIntegrationService::instance()->setChatSession($credentials, Session::getSessionId()); $authService->setRememberMe($user); } } } }
/** * @param array $params * @throws Exception */ public function authenticate(array $params) { $UserService = UserService::instance(); $authService = AuthenticationService::instance(); if (!isset($params['oauth_token']) || empty($params['oauth_token']) || !isset($params['oauth_verifier']) || empty($params['oauth_verifier'])) { throw new Exception('Authentication failed'); } $oauth = Session::set('oauth'); if ($params['oauth_token'] !== $oauth['oauth_token']) { throw new Exception('Invalid login session'); } $twitterOAuthConf = Config::$a['oauth']['providers']['twitter']; $tmhOAuth = new \tmhOAuth(array('consumer_key' => $twitterOAuthConf['clientId'], 'consumer_secret' => $twitterOAuthConf['clientSecret'], 'token' => $oauth['oauth_token'], 'secret' => $oauth['oauth_token_secret'], 'curl_connecttimeout' => Config::$a['curl']['connecttimeout'], 'curl_timeout' => Config::$a['curl']['timeout'], 'curl_ssl_verifypeer' => Config::$a['curl']['verifypeer'])); $code = $tmhOAuth->user_request(array('method' => 'POST', 'url' => $tmhOAuth->url('oauth/access_token', ''), 'params' => array('oauth_verifier' => trim($params['oauth_verifier'])))); if ($code != 200) { throw new Exception('Failed to retrieve user data'); } $data = $tmhOAuth->extract_params($tmhOAuth->response['response']); $authCreds = $this->getAuthCredentials($oauth['oauth_token'], $data); $authCredHandler = new AuthenticationRedirectionFilter(); return $authCredHandler->execute($authCreds); }
/** * @Route ("/admin/user/{id}/subscription/{subscriptionId}/save") * @Route ("/admin/user/{id}/subscription/save") * @Secure ({"ADMIN"}) * @HttpMethod ({"POST"}) * * @param array $params * @param ViewModel $model * @throws Exception * @return string */ public function subscriptionSave(array $params, ViewModel $model) { FilterParams::required($params, 'subscriptionType'); FilterParams::required($params, 'status'); FilterParams::required($params, 'createdDate'); FilterParams::required($params, 'endDate'); $subscriptionsService = SubscriptionsService::instance(); $subscriptionType = $subscriptionsService->getSubscriptionType($params['subscriptionType']); $subscription = array(); $subscription['subscriptionType'] = $subscriptionType['id']; $subscription['subscriptionTier'] = $subscriptionType['tier']; $subscription['status'] = $params['status']; $subscription['createdDate'] = $params['createdDate']; $subscription['endDate'] = $params['endDate']; $subscription['userId'] = $params['id']; $subscription['subscriptionSource'] = isset($params['subscriptionSource']) && !empty($params['subscriptionSource']) ? $params['subscriptionSource'] : Config::$a['subscriptionType']; if (isset($params['subscriptionId']) && !empty($params['subscriptionId'])) { $subscription['subscriptionId'] = $params['subscriptionId']; $subscriptionId = $subscription['subscriptionId']; $subscriptionsService->updateSubscription($subscription); Session::set('modelSuccess', 'Subscription updated!'); } else { $subscriptionId = $subscriptionsService->addSubscription($subscription); Session::set('modelSuccess', 'Subscription created!'); } $authService = AuthenticationService::instance(); $authService->flagUserForUpdate($params['id']); return 'redirect: /admin/user/' . urlencode($params['id']) . '/subscription/' . urlencode($subscriptionId) . '/edit'; }
/** * @Route ("/profile/update") * @HttpMethod ({"POST"}) * @Secure ({"USER"}) * * @param array $params * @return string * @throws Exception * @throws \Doctrine\DBAL\DBALException * @throws \Exception */ public function profileSave(array $params) { // Get user $userService = UserService::instance(); $authenticationService = AuthenticationService::instance(); $userId = Session::getCredentials()->getUserId(); $user = $userService->getUserById($userId); if (empty($user)) { throw new Exception('Invalid user'); } $username = isset($params['username']) && !empty($params['username']) ? $params['username'] : $user['username']; $email = isset($params['email']) && !empty($params['email']) ? $params['email'] : $user['email']; $country = isset($params['country']) && !empty($params['country']) ? $params['country'] : $user['country']; $allowGifting = isset($params['allowGifting']) ? $params['allowGifting'] : $user['allowGifting']; $minecraftname = isset($params['minecraftname']) && !empty($params['minecraftname']) ? $params['minecraftname'] : $user['minecraftname']; try { $authenticationService->validateUsername($username, $user); $authenticationService->validateEmail($email, $user); if (!empty($country)) { $countryArr = Country::getCountryByCode($country); if (empty($countryArr)) { throw new Exception('Invalid country'); } $country = $countryArr['alpha-2']; } } catch (Exception $e) { Session::set('modelError', $e->getMessage()); return 'redirect: /profile'; } // Date for update $userData = array('username' => $username, 'country' => $country, 'email' => $email, 'minecraftname' => $minecraftname, 'allowGifting' => $allowGifting); // Is the user changing their name? if (strcasecmp($username, $user['username']) !== 0) { $nameChangeCount = intval($user['nameChangedCount']); // have they hit their limit if ($nameChangeCount >= Config::$a['profile']['nameChangeLimit']) { throw new Exception('You have reached your name change limit'); } else { $userData['nameChangedDate'] = Date::getDateTime('NOW')->format('Y-m-d H:i:s'); $userData['nameChangedCount'] = $nameChangeCount + 1; } } try { // Update user $userService->updateUser($user['userId'], $userData); } catch (\Doctrine\DBAL\DBALException $e) { // get PDO exception, extract info $info = $e->getPrevious()->errorInfo; // a unique key constraint failure if ($info[0] === "23000") { // extract key name if (!preg_match("/^Duplicate entry '.+' for key '(.+)'\$/iu", $info[2], $match)) { throw $e; } // WELL F**K I GUESS ITS NOT MYSQL $key = $match[1]; $keyToField = array('minecraftname' => '"Minecraft name"'); throw new Exception('Duplicate value for ' . $keyToField[$key]); } } $authenticationService->flagUserForUpdate($user['userId']); Session::set('modelSuccess', 'Your profile has been updated'); return 'redirect: /profile'; }
/** * @Route ("/api/addtwitchsubscription") * @HttpMethod ({"POST"}) * * Expects the following POST variables: * privatekey=XXXXXXXX * * @param array $params * @return Response */ public function addSubscription(array $params) { $response = array(); // TODO GET RID OF THE COPY PASTE try { FilterParams::required($params, 'privatekey'); if (!$this->checkPrivateKey($params['privatekey'])) { throw new Exception('Invalid shared private key.'); } /* * The expected json schema is: {"123": 1, "431": 0} * where the key is the twitch user id and the value is whether * the user is a subscriber or not */ $data = json_decode(file_get_contents('php://input'), true); $userService = UserService::instance(); $authid = $userService->getTwitchIDFromNick($data['nick']); if ($authid) { $users = $userService->updateTwitchSubscriptions(array($authid => 1)); $chatIntegrationService = ChatIntegrationService::instance(); $authenticationService = AuthenticationService::instance(); foreach ($users as $user) { $authenticationService->flagUserForUpdate($user['userId']); if (!$user['istwitchsubscriber']) { // do not announce non-subs continue; } $chatIntegrationService->sendBroadcast(sprintf("%s is now a Twitch subscriber!", $user['username'])); } } $response = new Response(Http::STATUS_NO_CONTENT); } catch (Exception $e) { $response['success'] = false; $response['error'] = $e->getMessage(); $response = new Response(Http::STATUS_BAD_REQUEST, json_encode($response)); $response->addHeader(Http::HEADER_CONTENTTYPE, MimeType::JSON); } return $response; }
use Destiny\Common\Session; use Destiny\Common\Config; use Destiny\Common\Routing\Router; use Destiny\Common\Routing\RouteAnnotationClassLoader; use Destiny\Common\DirectoryClassIterator; use Destiny\Common\Authentication\RememberMeService; use Destiny\Common\Authentication\AuthenticationService; use Doctrine\Common\Annotations\FileCacheReader; use Doctrine\Common\Annotations\AnnotationReader; use Destiny\Common\Request; ini_set('session.gc_maxlifetime', 5 * 60 * 60); $context = new \stdClass(); $context->log = 'web'; require __DIR__ . '/../lib/boot.php'; $app = Application::instance(); $app->setRouter(new Router()); $app->setAnnotationReader(new FileCacheReader(new AnnotationReader(), realpath(Config::$a['cache']['path']) . '/annotation/')); // Annotation reader and routing RouteAnnotationClassLoader::loadClasses(new DirectoryClassIterator(_BASEDIR . '/lib/', 'Destiny/Controllers/'), $app->getAnnotationReader()); // Setup user session $session = new SessionInstance(); $session->setSessionCookie(new SessionCookie(Config::$a['cookie'])); $session->setCredentials(new SessionCredentials()); $app->setSession($session); // Start the session if a valid session cookie is found Session::start(Session::START_IFCOOKIE); // Startup the remember me and auth service AuthenticationService::instance()->init(); RememberMeService::instance()->init(); // Attempts to find a route and execute it $app->executeRequest(new Request());
/** * @Route ("/admin/user/{userId}/ban/remove") * @Secure ({"ADMIN"}) * * @param array $params */ public function removeBan(array $params) { if (!isset($params['userId']) || empty($params['userId'])) { throw new Exception('userId required'); } $userService = UserService::instance(); $authenticationService = AuthenticationService::instance(); // if there were rows modified there were bans removed, so an update is // required, removeUserBan returns the number of rows modified if ($userService->removeUserBan($params['userId'])) { $authenticationService->flagUserForUpdate($params['userId']); } if (isset($params['follow']) and substr($params['follow'], 0, 1) == '/') { return 'redirect: ' . $params['follow']; } return 'redirect: /admin/user/' . $params['userId'] . '/edit'; }
/** * @Route ("/subscription/process") * @Secure ({"USER"}) * @Transactional * * We were redirected here from PayPal after the buyer approved/cancelled the payment * * @param array $params */ public function subscriptionProcess(array $params, ViewModel $model) { FilterParams::isRequired($params, 'orderId'); FilterParams::isRequired($params, 'token'); FilterParams::isThere($params, 'success'); $ordersService = OrdersService::instance(); $userService = UserService::instance(); $subscriptionsService = SubscriptionsService::instance(); $payPalApiService = PayPalApiService::instance(); $chatIntegrationService = ChatIntegrationService::instance(); $authenticationService = AuthenticationService::instance(); $userId = Session::getCredentials()->getUserId(); // Get the order $order = $ordersService->getOrderByIdAndUserId($params['orderId'], $userId); if (empty($order) || strcasecmp($order['state'], OrderStatus::_NEW) !== 0) { throw new Exception('Invalid order record'); } try { // If we got a failed response URL if ($params['success'] == '0' || $params['success'] == 'false' || $params['success'] === false) { throw new Exception('Order request failed'); } // Get the subscription from the order $orderSubscription = $subscriptionsService->getSubscriptionByOrderId($order['orderId']); $subscriptionUser = $userService->getUserById($orderSubscription['userId']); // Make sure the subscription is valid if (empty($orderSubscription)) { throw new Exception('Invalid order subscription'); } // Make sure the subscription is either owned or gifted by the user if ($subscriptionUser['userId'] != $userId && $orderSubscription['gifter'] != $userId) { throw new Exception('Invalid order subscription'); } $subscriptionType = $subscriptionsService->getSubscriptionType($orderSubscription['subscriptionType']); $paymentProfile = $ordersService->getPaymentProfileByOrderId($order['orderId']); // Get the checkout info $ecResponse = $payPalApiService->retrieveCheckoutInfo($params['token']); if (!isset($ecResponse) || $ecResponse->Ack != 'Success') { throw new Exception('Failed to retrieve express checkout details'); } // Moved this down here, as if the order status is error, the payerID is not returned FilterParams::isRequired($params, 'PayerID'); // Point of no return - we only every want a person to get here if their order was a successful sequence Session::set('token'); Session::set('orderId'); // Recurring payment if (!empty($paymentProfile)) { $createRPProfileResponse = $payPalApiService->createRecurringPaymentProfile($paymentProfile, $params['token'], $subscriptionType); if (!isset($createRPProfileResponse) || $createRPProfileResponse->Ack != 'Success') { throw new Exception('Failed to create recurring payment request'); } $paymentProfileId = $createRPProfileResponse->CreateRecurringPaymentsProfileResponseDetails->ProfileID; $paymentStatus = $createRPProfileResponse->CreateRecurringPaymentsProfileResponseDetails->ProfileStatus; if (empty($paymentProfileId)) { throw new Exception('Invalid recurring payment profileId returned from Paypal'); } // Set the payment profile to active, and paymetProfileId $ordersService->updatePaymentProfileId($paymentProfile['profileId'], $paymentProfileId, $paymentStatus); // Update the payment profile $subscriptionsService->updateSubscriptionPaymentProfile($orderSubscription['subscriptionId'], $paymentProfile['profileId'], true); } // Complete the checkout $DoECResponse = $payPalApiService->getECPaymentResponse($params['PayerID'], $params['token'], $order); if (isset($DoECResponse) && $DoECResponse->Ack == 'Success') { if (isset($DoECResponse->DoExpressCheckoutPaymentResponseDetails->PaymentInfo)) { $payPalApiService->recordECPayments($DoECResponse, $params['PayerID'], $order); $ordersService->updateOrderState($order['orderId'], $order['state']); } else { throw new Exception('No payments for express checkout order'); } } else { throw new Exception($DoECResponse->Errors[0]->LongMessage); } // If the user already has a subscription and ONLY if this subscription was NOT a gift if (!isset($orderSubscription['gifter']) || empty($orderSubscription['gifter'])) { $activeSubscription = $subscriptionsService->getUserActiveSubscription($subscriptionUser['userId']); if (!empty($activeSubscription)) { // Cancel any attached payment profiles $ordersService = OrdersService::instance(); $paymentProfile = $ordersService->getPaymentProfileById($activeSubscription['paymentProfileId']); if (!empty($paymentProfile)) { $payPalApiService->cancelPaymentProfile($activeSubscription, $paymentProfile); $subscriptionsService->updateSubscriptionRecurring($activeSubscription['subscriptionId'], false); } // Cancel the active subscription $subscriptionsService->updateSubscriptionState($activeSubscription['subscriptionId'], SubscriptionStatus::CANCELLED); } } // Check if this is a gift, check that the giftee is still eligable if (!empty($orderSubscription['gifter']) && !$subscriptionsService->getCanUserReceiveGift($userId, $subscriptionUser['userId'])) { // Update the state to ERROR and log a critical error Application::instance()->getLogger()->critical('Duplicate subscription attempt, Gifter: %d GifteeId: %d, OrderId: %d', $userId, $subscriptionUser['userId'], $order['orderId']); $subscriptionsService->updateSubscriptionState($orderSubscription['subscriptionId'], SubscriptionStatus::ERROR); } else { // Unban the user if a ban is found $ban = $userService->getUserActiveBan($subscriptionUser['userId']); // only unban the user if the ban is non-permanent or the tier of the subscription is >= 2 // we unban the user if no ban is found because it also unmutes if (empty($ban) or (!empty($ban['endtimestamp']) or $orderSubscription['subscriptionTier'] >= 2)) { $chatIntegrationService->sendUnban($subscriptionUser['userId']); } // Activate the subscription (state) $subscriptionsService->updateSubscriptionState($orderSubscription['subscriptionId'], SubscriptionStatus::ACTIVE); // Flag the user for 'update' $authenticationService->flagUserForUpdate($subscriptionUser['userId']); // Random emote $randomEmote = Config::$a['chat']['customemotes'][array_rand(Config::$a['chat']['customemotes'])]; // Broadcast if (!empty($orderSubscription['gifter'])) { $gifter = $userService->getUserById($orderSubscription['gifter']); $userName = $gifter['username']; $chatIntegrationService->sendBroadcast(sprintf("%s is now a %s subscriber! gifted by %s %s", $subscriptionUser['username'], $subscriptionType['tierLabel'], $gifter['username'], $randomEmote)); } else { $userName = $subscriptionUser['username']; $chatIntegrationService->sendBroadcast(sprintf("%s is now a %s subscriber! %s", $subscriptionUser['username'], $subscriptionType['tierLabel'], $randomEmote)); } // Get the subscription message, and remove it from the session $subMessage = Session::set('subMessage'); if (!empty($subMessage)) { $chatIntegrationService->sendBroadcast(sprintf("%s: %s", $userName, $subMessage)); } } // Redirect to completion page return 'redirect: /subscription/' . urlencode($order['orderId']) . '/complete'; } catch (Exception $e) { if (!empty($order)) { $ordersService->updateOrderState($order['orderId'], OrderStatus::ERROR); } if (!empty($paymentProfile)) { $ordersService->updatePaymentStatus($paymentProfile['paymentId'], PaymentStatus::ERROR); } if (!empty($orderSubscription)) { $subscriptionsService->updateSubscriptionState($orderSubscription['subscriptionId'], SubscriptionStatus::ERROR); } $log = Application::instance()->getLogger(); $log->error($e->getMessage(), $order); return 'redirect: /subscription/' . urlencode($order['orderId']) . '/error'; } }
<?php use Destiny\Common\Application; use Destiny\Common\SessionCredentials; use Destiny\Common\SessionInstance; use Destiny\Common\Cookie; use Destiny\Common\Config; use Destiny\Common\Authentication\AuthenticationService; use Destiny\Common\Request; ini_set('session.gc_maxlifetime', 5 * 60 * 60); require __DIR__ . '/../lib/boot.php'; $app = Application::instance(); // Setup user session $session = new SessionInstance(); $session->setSessionCookie(new Cookie('sid', Config::$a['cookie'])); $session->setRememberMeCookie(new Cookie('rememberme', Config::$a['cookie'])); $session->setCredentials(new SessionCredentials()); $app->setSession($session); // Startup the authentication service, handles logged in session, remember me session AuthenticationService::instance()->startSession(); // Attempts to find a route and execute it $app->executeRequest(new Request());
/** * @Route ("/subscription/process") * @Secure ({"USER"}) * * We were redirected here from PayPal after the buyer approved/cancelled the payment * * @param array $params * @return string * @throws Exception * @throws \Destiny\Common\Utils\FilterParamsException * TODO clean this method up */ public function subscriptionProcess(array $params) { FilterParams::required($params, 'subscriptionId'); FilterParams::required($params, 'token'); FilterParams::declared($params, 'success'); $userId = Session::getCredentials()->getUserId(); $userService = UserService::instance(); $ordersService = OrdersService::instance(); $subscriptionsService = SubscriptionsService::instance(); $payPalApiService = PayPalApiService::instance(); $chatIntegrationService = ChatIntegrationService::instance(); $authenticationService = AuthenticationService::instance(); $log = Application::instance()->getLogger(); $subscription = $subscriptionsService->getSubscriptionById($params['subscriptionId']); if (empty($subscription) || strcasecmp($subscription['status'], SubscriptionStatus::_NEW) !== 0) { throw new Exception('Invalid subscription record'); } try { $subscriptionType = $subscriptionsService->getSubscriptionType($subscription['subscriptionType']); $user = $userService->getUserById($subscription['userId']); if ($user['userId'] != $userId && $subscription['gifter'] != $userId) { throw new Exception('Invalid subscription'); } if ($params['success'] == '0' || $params['success'] == 'false' || $params['success'] === false) { throw new Exception('Order request failed'); } if (!$payPalApiService->retrieveCheckoutInfo($params['token'])) { throw new Exception('Failed to retrieve express checkout details'); } FilterParams::required($params, 'PayerID'); // if the order status is an error, the payerID is not returned Session::set('subscriptionId'); Session::set('token'); // Create the payment profile // Payment date is 1 day before subscription rolls over. if ($subscription['recurring'] == 1 || $subscription['recurring'] == true) { $startPaymentDate = Date::getDateTime(); $nextPaymentDate = Date::getDateTime(); $nextPaymentDate->modify('+' . $subscriptionType['billingFrequency'] . ' ' . strtolower($subscriptionType['billingPeriod'])); $nextPaymentDate->modify('-1 DAY'); $reference = $subscription['userId'] . '-' . $subscription['subscriptionId']; $paymentProfileId = $payPalApiService->createRecurringPaymentProfile($params['token'], $reference, $user['username'], $nextPaymentDate, $subscriptionType); if (empty($paymentProfileId)) { throw new Exception('Invalid recurring payment profileId returned from Paypal'); } $subscriptionsService->updateSubscription(array('subscriptionId' => $subscription['subscriptionId'], 'paymentStatus' => PaymentStatus::ACTIVE, 'paymentProfileId' => $paymentProfileId, 'billingStartDate' => $startPaymentDate->format('Y-m-d H:i:s'), 'billingNextDate' => $nextPaymentDate->format('Y-m-d H:i:s'))); } // Record the payments as well as check if any are not in the completed state // we put the subscription into "PENDING" state if a payment is found not completed $subscriptionStatus = SubscriptionStatus::ACTIVE; $DoECResponse = $payPalApiService->getECPaymentResponse($params['PayerID'], $params['token'], $subscriptionType['amount']); $payments = $payPalApiService->getResponsePayments($DoECResponse); foreach ($payments as $payment) { $payment['subscriptionId'] = $subscription['subscriptionId']; $payment['payerId'] = $params['PayerID']; $ordersService->addPayment($payment); // TODO: Payment provides no way of telling if the transaction with ALL payments was successful if ($payment['paymentStatus'] != PaymentStatus::COMPLETED) { $subscriptionStatus = SubscriptionStatus::PENDING; } } // Update subscription status $subscriptionsService->updateSubscription(array('subscriptionId' => $subscription['subscriptionId'], 'status' => $subscriptionStatus)); } catch (Exception $e) { $subscriptionsService->updateSubscription(array('subscriptionId' => $subscription['subscriptionId'], 'status' => SubscriptionStatus::ERROR)); $log->critical($e->getMessage(), $subscription); return 'redirect: /subscription/' . urlencode($subscription['subscriptionId']) . '/error'; } // only unban the user if the ban is non-permanent or the tier of the subscription is >= 2 // we unban the user if no ban is found because it also unmutes $ban = $userService->getUserActiveBan($user['userId']); if (empty($ban) or (!empty($ban['endtimestamp']) or $subscriptionType['tier'] >= 2)) { $chatIntegrationService->sendUnban($user['userId']); } // Broadcast $randomEmote = Config::$a['chat']['customemotes'][array_rand(Config::$a['chat']['customemotes'])]; if (!empty($subscription['gifter'])) { $gifter = $userService->getUserById($subscription['gifter']); $userName = $gifter['username']; $chatIntegrationService->sendBroadcast(sprintf("%s is now a %s subscriber! gifted by %s %s", $user['username'], $subscriptionType['tierLabel'], $gifter['username'], $randomEmote)); } else { $userName = $user['username']; $chatIntegrationService->sendBroadcast(sprintf("%s is now a %s subscriber! %s", $user['username'], $subscriptionType['tierLabel'], $randomEmote)); } $subMessage = Session::set('subMessage'); if (!empty($subMessage)) { $chatIntegrationService->sendBroadcast(sprintf("%s: %s", $userName, $subMessage)); } // Update the user $authenticationService->flagUserForUpdate($user['userId']); // Redirect to completion page return 'redirect: /subscription/' . urlencode($subscription['subscriptionId']) . '/complete'; }
/** * @Route ("/register") * @HttpMethod ({"POST"}) * @Transactional * * Handle the confirmation request * @param array $params * @throws Exception */ public function registerProcess(array $params, ViewModel $model, Request $request) { $userService = UserService::instance(); $authService = AuthenticationService::instance(); $authCreds = $this->getSessionAuthenticationCredentials($params); $username = isset($params['username']) && !empty($params['username']) ? $params['username'] : ''; $email = isset($params['email']) && !empty($params['email']) ? $params['email'] : ''; $country = isset($params['country']) && !empty($params['country']) ? $params['country'] : ''; $rememberme = isset($params['rememberme']) && !empty($params['rememberme']) ? true : false; $authCreds->setUsername($username); $authCreds->setEmail($email); try { if (!isset($params['g-recaptcha-response']) || empty($params['g-recaptcha-response'])) { throw new Exception('You must solve the recaptcha.'); } $googleRecaptchaHandler = new GoogleRecaptchaHandler(); $googleRecaptchaHandler->resolve(Config::$a['g-recaptcha']['secret'], $params['g-recaptcha-response'], $request->ipAddress()); $authService->validateUsername($username); $authService->validateEmail($email); if (!empty($country)) { $countryArr = Country::getCountryByCode($country); if (empty($countryArr)) { throw new Exception('Invalid country'); } $country = $countryArr['alpha-2']; } $user = array(); $user['username'] = $username; $user['email'] = $email; $user['userStatus'] = 'Active'; $user['country'] = $country; $user['userId'] = $userService->addUser($user); $userService->addUserAuthProfile(array('userId' => $user['userId'], 'authProvider' => $authCreds->getAuthProvider(), 'authId' => $authCreds->getAuthId(), 'authCode' => $authCreds->getAuthCode(), 'authDetail' => $authCreds->getAuthDetail())); Session::set('authSession'); $authCredHandler = new AuthenticationRedirectionFilter(); return $authCredHandler->execute($authCreds); } catch (Exception $e) { $model->title = 'Register Error'; $model->username = $username; $model->email = $email; $model->follow = isset($params['follow']) ? $params['follow'] : ''; $model->authProvider = $authCreds->getAuthProvider(); $model->code = $authCreds->getAuthCode(); $model->error = $e; return 'register'; } }
/** * @Route ("/profile/update") * @HttpMethod ({"POST"}) * @Secure ({"USER"}) * @Transactional * * @param array $params * @param ViewModel $model * @throws Exception * @return string */ public function profileSave(array $params, ViewModel $model) { // Get user $userService = UserService::instance(); $userFeaturesService = UserFeaturesService::instance(); $subscriptionsService = SubscriptionsService::instance(); $authenticationService = AuthenticationService::instance(); $userId = Session::getCredentials()->getUserId(); $user = $userService->getUserById($userId); if (empty($user)) { throw new Exception('Invalid user'); } $username = isset($params['username']) && !empty($params['username']) ? $params['username'] : $user['username']; $email = isset($params['email']) && !empty($params['email']) ? $params['email'] : $user['email']; $country = isset($params['country']) && !empty($params['country']) ? $params['country'] : $user['country']; $allowGifting = isset($params['allowGifting']) ? $params['allowGifting'] : $user['allowGifting']; try { $authenticationService->validateUsername($username, $user); $authenticationService->validateEmail($email, $user); if (!empty($country)) { $countryArr = Country::getCountryByCode($country); if (empty($countryArr)) { throw new Exception('Invalid country'); } $country = $countryArr['alpha-2']; } } catch (Exception $e) { Session::set('modelError', $e->getMessage()); return 'redirect: /profile'; } // Date for update $userData = array('username' => $username, 'country' => $country, 'email' => $email, 'allowGifting' => $allowGifting); // Is the user changing their name? if (strcasecmp($username, $user['username']) !== 0) { $nameChangeCount = intval($user['nameChangedCount']); // have they hit their limit if ($nameChangeCount >= Config::$a['profile']['nameChangeLimit']) { throw new Exception('You have reached your name change limit'); } else { $userData['nameChangedDate'] = Date::getDateTime('NOW')->format('Y-m-d H:i:s'); $userData['nameChangedCount'] = $nameChangeCount + 1; } } // Update user $userService->updateUser($user['userId'], $userData); $authenticationService->flagUserForUpdate($user['userId']); Session::set('modelSuccess', 'Your profile has been updated'); return 'redirect: /profile'; }
/** * @Route ("/logout") * * @param array $params */ public function logout(array $params) { AuthenticationService::instance()->logout(); return 'redirect: /'; }
/** * Handles the IPN message * * @param PPIPNMessage $ipnMessage */ protected function handleIPNTransaction($txnId, $txnType, array $data) { $log = Application::instance()->getLogger(); $orderService = OrdersService::instance(); $subService = SubscriptionsService::instance(); $authService = AuthenticationService::instance(); switch (strtolower($txnType)) { // Post back from checkout, make sure the payment lines up // This is sent when a express checkout has been performed by a user case 'express_checkout': $payment = $orderService->getPaymentByTransactionId($txnId); if (!empty($payment)) { // Make sure the payment values are the same if (number_format($payment['amount'], 2) != number_format($data['mc_gross'], 2)) { throw new Exception('Amount for payment do not match'); } // Update the payment status $orderService->updatePaymentStatus($payment['paymentId'], $data['payment_status']); $log->notice(sprintf('Updated payment status %s status %s', $data['txn_id'], $data['payment_status'])); // If the payment status WAS PENDING, and the IPN payment status is COMPLETED // Then we need to activate the attached subscription and complete the order // This is for the ECHECK payment method if (strcasecmp($payment['paymentStatus'], PaymentStatus::PENDING) === 0 && strcasecmp($data['payment_status'], PaymentStatus::COMPLETED) === 0) { $order = $orderService->getOrderByPaymentId($payment['paymentId']); if (!empty($order)) { $orderService->updateOrderState($order['orderId'], OrderStatus::COMPLETED); $log->debug(sprintf('Updated order status %s status %s', $order['orderId'], OrderStatus::COMPLETED)); $subscription = $subService->getUserPendingSubscription($order['userId']); if (!empty($subscription)) { $subService->updateSubscriptionState($subscription['subscriptionId'], SubscriptionStatus::ACTIVE); $log->notice(sprintf('Updated subscription status %s status %s', $order['orderId'], SubscriptionStatus::ACTIVE)); $authService->flagUserForUpdate($subscription['userId']); } } } } else { $log->info(sprintf('Express checkout IPN called, but no payment found [%s]', $txnId)); } break; // Recurring payment, renew subscriptions, or set to pending depending on the type // This is sent from paypal when a recurring payment is billed // Recurring payment, renew subscriptions, or set to pending depending on the type // This is sent from paypal when a recurring payment is billed case 'recurring_payment': if (!isset($data['payment_status'])) { throw new Exception('Invalid payment status'); } if (!isset($data['next_payment_date'])) { throw new Exception('Invalid next_payment_date'); } $paymentProfile = $this->getPaymentProfile($data); // We dont care about what state the sub is in.... $subscription = $subService->getSubscriptionByOrderId($paymentProfile['orderId']); if (empty($subscription)) { $log->critical('Invalid recurring_payment', $data); throw new Exception('Invalid subscription for recurring payment'); } if ($subscription['userId'] != $paymentProfile['userId'] && $subscription['gifter'] != $paymentProfile['userId']) { throw new Exception(sprintf('Invalid subscription for user %s', $subscription['userId'])); } $nextPaymentDate = Date::getDateTime($data['next_payment_date']); $orderService->updatePaymentProfileNextPayment($paymentProfile['profileId'], $nextPaymentDate); // Update the subscription end date regardless if the payment was successful or not // We dont actually know if paypal moves the automatic payment forward if one fails and is then manually processed $end = Date::getDateTime($subscription['endDate']); $end->modify('+' . $paymentProfile['billingFrequency'] . ' ' . strtolower($paymentProfile['billingPeriod'])); // Update subscription end-date $subService->updateSubscriptionDateEnd($subscription['subscriptionId'], $end); $log->debug(sprintf('Update Subscription end date %s [%s]', $subscription['subscriptionId'], $end->format(Date::FORMAT))); // Change the subscription state depending on the payment state if (strcasecmp($data['payment_status'], PaymentStatus::PENDING) === 0) { $subService->updateSubscriptionState($subscription['subscriptionId'], SubscriptionStatus::PENDING); $log->debug(sprintf('Updated subscription state %s status %s', $subscription['subscriptionId'], SubscriptionStatus::PENDING)); } else { if (strcasecmp($data['payment_status'], PaymentStatus::COMPLETED) === 0) { $subService->updateSubscriptionState($subscription['subscriptionId'], SubscriptionStatus::ACTIVE); $log->debug(sprintf('Updated subscription %s status %s', $subscription['subscriptionId'], SubscriptionStatus::ACTIVE)); } else { $log->notice(sprintf('Subscription status %s not changed for payment profile %s', $subscription['subscriptionId'], $paymentProfile['profileId'])); } } // Add a payment to the order $payment = array(); $payment['orderId'] = $paymentProfile['orderId']; $payment['payerId'] = $data['payer_id']; $payment['amount'] = $data['mc_gross']; $payment['currency'] = $data['mc_currency']; $payment['transactionId'] = $txnId; $payment['transactionType'] = $txnType; $payment['paymentType'] = $data['payment_type']; $payment['paymentStatus'] = $data['payment_status']; $payment['paymentDate'] = Date::getDateTime($data['payment_date'])->format('Y-m-d H:i:s'); $orderService->addOrderPayment($payment); $log->notice(sprintf('Added order payment %s status %s', $data['recurring_payment_id'], $data['profile_status'])); $authService->flagUserForUpdate($subscription['userId']); break; // Sent if user cancels subscription from Paypal's site. // Sent if user cancels subscription from Paypal's site. case 'recurring_payment_profile_cancel': $paymentProfile = $this->getPaymentProfile($data); $orderService->updatePaymentProfileState($paymentProfile['profileId'], $data['profile_status']); $log->debug(sprintf('Payment profile cancelled %s status %s', $data['recurring_payment_id'], $data['profile_status'])); break; // sent on first postback when the user subscribes // sent on first postback when the user subscribes case 'recurring_payment_profile_created': $paymentProfile = $this->getPaymentProfile($data); if (strcasecmp($data['profile_status'], 'Active') === 0) { $data['profile_status'] = 'ActiveProfile'; } $orderService->updatePaymentProfileState($paymentProfile['profileId'], $data['profile_status']); $log->debug(sprintf('Updated payment profile %s status %s', $data['recurring_payment_id'], $data['profile_status'])); break; } }