soon_limit = 30; parent::__construct(); } abstract public function authentication_URL(); abstract public function access_token_URL(); abstract public function renew_token($token): array; abstract protected function set_token_validity($validity); public function redirect_url() { return get_site_url(); } /** * Takes an OAuth request token and exchanges it for an access token. * * @param $request_token */ public function get_access_token($request_token) { $code = $request_token['code']; $state_args = explode('::', $request_token['state']); if (md5($this->client_secret . $this->provider) === $state_args[0]) { $url = urldecode($state_args[1]); $response = Photonic::http( $this->access_token_URL(), 'POST', [ 'code' => $code, 'grant_type' => 'authorization_code', 'client_id' => $this->client_id, 'client_secret' => $this->client_secret, 'redirect_uri' => $this->redirect_url(), ] ); if (is_wp_error($response)) { $url = add_query_arg('error', $response->get_error_code(), $url); } elseif (empty($response)) { $url = add_query_arg('error', 'null', $url); } } else { $url = remove_query_arg(['token', 'code', 'state']); } wp_safe_redirect($url); exit(); } /** * @param $base_token */ public function authenticate($base_token) { $photonic_authentication = get_option('photonic_authentication'); if (!isset($photonic_authentication)) { $photonic_authentication = []; } $transient_token = get_transient('photonic_' . $this->provider . '_token'); if (empty($transient_token) && !isset($photonic_authentication[$this->provider]) && !empty($base_token)) { // Nothing is in the authentication option, but there is a token in overall Photonic Options. // Refresh it if required, and save it as a transient via renew_token. list($token, $error) = $this->renew_token($base_token); } elseif ($transient_token || isset($photonic_authentication[$this->provider])) { $token = empty($transient_token) ? $photonic_authentication[$this->provider] : $transient_token; if (!empty($token)) { if (empty($transient_token) && !($this->is_token_expired($token) || $this->is_token_expiring_soon($this->soon_limit) > 0)) { set_transient('photonic_' . $this->provider . '_token', $token, $token['oauth_token_expires']); $this->set_token_validity(true); } elseif ($this->is_token_expired($token) || $this->is_token_expiring_soon($this->soon_limit) > 0) { list($token, $error) = $this->renew_token($base_token); } else { $this->set_token_validity(true); } } else { list($token, $error) = $this->renew_token($base_token); } } if (!empty($token)) { $this->access_token = $token['oauth_token']; $this->auth_error = ''; } else { $this->set_token_validity(false); if (!empty($error)) { $this->auth_error = $error; } else { $this->auth_error = ''; } } } public function is_token_expired($token) { if (empty($token)) { return true; } if (!isset($token['oauth_token']) || !isset($token['oauth_token_created']) || !isset($token['oauth_token_expires'])) { return true; } if (!isset($token['client_id']) || (isset($token['client_id']) && $token['client_id'] !== $this->client_id)) { return true; } $current = time(); if ($token['oauth_token_created'] + $token['oauth_token_expires'] < $current) { return true; } return false; } /** * Checks if a token will expire soon. This is used to trigger a refresh for sources such as Instagram. Google uses a separate "Refresh Token", * so this is not applicable to it. The soon_limit defines how many days is "soon", and a refresh is triggered if the current date * is in the "soon" range. E.g. If you have a soon limit of 30 days, and your token expires in 15 days when you load the page, this method will * return true. * * For cases where the token does not exist yet, the method returns null. * * @param $soon_limit int Number of days to check the expiry limit for. * @return int|null If there is no token, return null. Otherwise, if there are < $soon_limit days left, return 1, if token is expired return -1, and if there is time return 0. */ abstract public function is_token_expiring_soon($soon_limit); /** * Takes a token response from a request token call, then puts it in an appropriate array. * * @param $response * @return array */ public function parse_token($response): array { $token = []; if (!is_wp_error($response) && is_array($response)) { $body = $response['body']; $body = json_decode($body); if (empty($body->error)) { $token['oauth_token'] = $body->access_token; $token['oauth_token_type'] = $body->token_type; $token['oauth_token_created'] = time(); $token['oauth_token_expires'] = $body->expires_in; if (!empty($body->refresh_token)) { $token['oauth_refresh_token'] = $body->refresh_token; } $this->set_token_validity(true); } else { $this->set_token_validity(false); } } return $token; } }