| 1 |
<?php |
| 2 |
|
| 3 |
namespace Photonic_Plugin\Admin; |
| 4 |
|
| 5 |
if (!current_user_can('edit_theme_options')) { |
| 6 |
wp_die(esc_html__('You are not authorized to use this capability.', 'photonic')); |
| 7 |
} |
| 8 |
|
| 9 |
use Photonic_Plugin\Core\Photonic; |
| 10 |
use Photonic_Plugin\Platforms\Authenticator; |
| 11 |
use Photonic_Plugin\Platforms\Base; |
| 12 |
use Photonic_Plugin\Platforms\Flickr; |
| 13 |
use Photonic_Plugin\Platforms\Google_Photos; |
| 14 |
use Photonic_Plugin\Platforms\Instagram; |
| 15 |
use Photonic_Plugin\Platforms\SmugMug; |
| 16 |
use Photonic_Plugin\Platforms\Zenfolio; |
| 17 |
use Photonic_Plugin\Platforms\DeviantArt; |
| 18 |
|
| 19 |
require_once 'Admin_Page.php'; |
| 20 |
|
| 21 |
class Authentication extends Admin_Page { |
| 22 |
private static ?Authentication $instance = null; |
| 23 |
|
| 24 |
private function __construct() { |
| 25 |
require_once PHOTONIC_PATH . '/Platforms/Zenfolio.php'; |
| 26 |
} |
| 27 |
|
| 28 |
public static function get_instance() { |
| 29 |
if (null === self::$instance) { |
| 30 |
self::$instance = new Authentication(); |
| 31 |
} |
| 32 |
return self::$instance; |
| 33 |
} |
| 34 |
|
| 35 |
public function render_content() { |
| 36 |
?> |
| 37 |
<form method="post" id="photonic-auth-form"> |
| 38 |
<h2 id="#photonic-flickr-auth-section" class="photonic-section">Flickr</h2> |
| 39 |
<?php $this->display_flickr(); ?> |
| 40 |
|
| 41 |
<h2 id="#photonic-smugmug-auth-section" class="photonic-section">SmugMug</h2> |
| 42 |
<?php $this->display_smugmug(); ?> |
| 43 |
|
| 44 |
<h2 id="#photonic-zenfolio-auth-section" class="photonic-section">Zenfolio</h2> |
| 45 |
<?php $this->display_zenfolio(); ?> |
| 46 |
|
| 47 |
<!-- <h2 id="#photonic-deviantart-auth-section" class="photonic-section">DeviantArt</h2> |
| 48 |
--><?php /*$this->display_deviantart(); */?> |
| 49 |
|
| 50 |
</form> |
| 51 |
<?php |
| 52 |
} |
| 53 |
|
| 54 |
private function display_flickr() { |
| 55 |
global $photonic_flickr_api_key, $photonic_flickr_api_secret, $photonic_flickr_access_token; |
| 56 |
$auth = [ |
| 57 |
'api_key' => trim($photonic_flickr_api_key), |
| 58 |
'api_secret' => trim($photonic_flickr_api_secret), |
| 59 |
'token' => trim($photonic_flickr_access_token), |
| 60 |
]; |
| 61 |
$this->show_token_section($auth, 'flickr', 'Flickr'); |
| 62 |
} |
| 63 |
|
| 64 |
private function display_smugmug() { |
| 65 |
global $photonic_smug_api_key, $photonic_smug_api_secret, $photonic_smug_access_token; |
| 66 |
$auth = [ |
| 67 |
'api_key' => !empty($photonic_smug_api_key) ? trim($photonic_smug_api_key) : '86MZ8N8TqJf5x2fQ4FRWXRtJ3C6Jm7XV', |
| 68 |
'api_secret' => trim($photonic_smug_api_secret), |
| 69 |
'token' => trim($photonic_smug_access_token), |
| 70 |
]; |
| 71 |
$this->show_token_section($auth, 'smug', 'SmugMug'); |
| 72 |
} |
| 73 |
|
| 74 |
private function display_zenfolio() { |
| 75 |
global $photonic_zenfolio_default_user; |
| 76 |
$gallery = Zenfolio::get_instance(); |
| 77 |
|
| 78 |
echo "<div class=\"photonic-token-header\">\n"; |
| 79 |
if (empty($photonic_zenfolio_default_user)) { |
| 80 |
/* Translators: 1: Menu location, untranslated */ |
| 81 |
echo sprintf(esc_html__('Please set up the default user for Zenfolio under %s', 'photonic'), '<em>Photonic → Settings → Zenfolio → Zenfolio Photo Settings → Default User</em>') . "\n"; |
| 82 |
} |
| 83 |
elseif (!empty($gallery->token)) { |
| 84 |
$this->print_auth_done_all_good(); |
| 85 |
} |
| 86 |
echo "</div>\n"; |
| 87 |
|
| 88 |
$response = Base::parse_parameters($_SERVER['QUERY_STRING'] ?? ''); |
| 89 |
if (!empty($photonic_zenfolio_default_user) && (empty($response['provider']) || 'zenfolio' !== $response['provider'])) { |
| 90 |
echo '<label>' . esc_html__('Password:', 'photonic') . "<input type='password' name='zenfolio-password' id='zenfolio-password'></label>"; |
| 91 |
} |
| 92 |
|
| 93 |
echo "<div style='display: block; width: 100%;'>\n"; |
| 94 |
if (!empty($photonic_zenfolio_default_user) && (empty($response['provider']) || 'zenfolio' !== $response['provider'])) { |
| 95 |
$nonce = wp_create_nonce('zenfolio-save-token'); |
| 96 |
echo "<a href='#' class='button button-primary' data-photonic-provider='zenfolio' style='margin-right: 1em;' data-photonic-nonce='" . esc_attr($nonce) . "'>" . esc_html__('Login and Authenticate', 'photonic') . '</a>'; |
| 97 |
} |
| 98 |
|
| 99 |
if (!empty($gallery->token)) { |
| 100 |
$nonce = wp_create_nonce('zenfolio-delete-token'); |
| 101 |
echo "<a href='#' class='button button-primary photonic-zenfolio-delete' data-photonic-nonce='" . esc_attr($nonce) . "'>" . esc_html__('Delete current Zenfolio authentication data', 'photonic') . '</a>'; |
| 102 |
} |
| 103 |
echo "</div>\n"; |
| 104 |
|
| 105 |
echo '<div class="result" id="zenfolio-result"> </div>'; |
| 106 |
} |
| 107 |
|
| 108 |
private function display_deviantart() { |
| 109 |
global $photonic_deviantart_client_id, $photonic_deviantart_client_secret, $photonic_deviantart_refresh_token; |
| 110 |
|
| 111 |
echo "<div class=\"photonic-token-header\">\n"; |
| 112 |
|
| 113 |
if (empty($photonic_deviantart_client_id) || empty($photonic_deviantart_client_secret)) { |
| 114 |
echo sprintf( |
| 115 |
/* Translators: 1: Location in menu, untranslated */ |
| 116 |
esc_html__('Please set up your DeviantArt Client ID and Client Secret under %s', 'photonic'), |
| 117 |
'<em>Photonic → Settings → DeviantArt → DeviantArt Settings</em>' |
| 118 |
); |
| 119 |
} |
| 120 |
else { |
| 121 |
require_once PHOTONIC_PATH . '/Platforms/DeviantArt.php'; |
| 122 |
|
| 123 |
$parameters = Base::parse_parameters($_SERVER['QUERY_STRING'] ?? ''); |
| 124 |
|
| 125 |
if (!empty($photonic_deviantart_refresh_token)) { |
| 126 |
$this->print_auth_done_all_good(); |
| 127 |
} |
| 128 |
|
| 129 |
echo "</div>\n"; |
| 130 |
echo "<div class=\"photonic-token-header\">\n"; |
| 131 |
echo "<p>\n"; |
| 132 |
esc_html_e('You first have to authorize Photonic to connect to your DeviantArt account.', 'photonic'); |
| 133 |
echo "</p>\n"; |
| 134 |
|
| 135 |
if (!isset($parameters['code']) || !isset($parameters['source']) || 'deviantart' !== $parameters['source']) { |
| 136 |
$url = add_query_arg('test', 'test'); |
| 137 |
$url = remove_query_arg('test', $url); |
| 138 |
$parameters = [ |
| 139 |
'response_type' => 'code', |
| 140 |
'client_id' => $photonic_deviantart_client_id, |
| 141 |
'redirect_uri' => admin_url('admin.php?page=photonic-auth&source=deviantart'), |
| 142 |
'scope' => 'basic browse', |
| 143 |
'access_type' => 'offline', |
| 144 |
'state' => md5($photonic_deviantart_client_secret . 'deviantart') . '::' . rawurlencode($url), |
| 145 |
'prompt' => 'consent', |
| 146 |
]; |
| 147 |
$url = 'https://www.deviantart.com/oauth2/authorize?' . DeviantArt::build_query($parameters); |
| 148 |
|
| 149 |
echo "<a href='" . esc_url($url) . "' class='button button-primary'>" . esc_html__('Step 1: Authenticate', 'photonic') . '</a>'; |
| 150 |
echo "</div>\n"; |
| 151 |
echo "<div class=\"photonic-token-header\">\n"; |
| 152 |
echo "<p>\n"; |
| 153 |
echo esc_html__('Next, you have to obtain the token.', 'photonic') . '<br/>'; |
| 154 |
echo "</p>\n"; |
| 155 |
echo "<span class='button photonic-helper-button-disabled'>" . |
| 156 |
esc_html__('Step 2: Obtain Token', 'photonic') . '</span>'; |
| 157 |
} |
| 158 |
else { |
| 159 |
echo "<span class='button photonic-helper-button-disabled'>" . |
| 160 |
esc_html__('Step 1: Authenticate', 'photonic') . '</span>'; |
| 161 |
echo "</div>\n"; |
| 162 |
echo "<div class=\"photonic-token-header\">\n"; |
| 163 |
echo esc_html__('Next, you have to obtain the token.', 'photonic') . '<br/>'; |
| 164 |
$nonce = wp_create_nonce('deviantart-obtain-token-' . $photonic_deviantart_client_secret); |
| 165 |
echo "<a href='#' class='button button-primary photonic-deviantart-refresh' data-photonic-nonce='" . esc_attr($nonce) . "' data-photonic-provider='deviantart'>" . |
| 166 |
esc_html__('Step 2: Obtain Token', 'photonic') . '</a>'; |
| 167 |
echo '<input type="hidden" value="' . esc_attr($parameters['code']) . '" id="photonic-deviantart-oauth-code"/>'; |
| 168 |
echo '<input type="hidden" value="' . esc_attr($parameters['state']) . '" id="photonic-deviantart-oauth-state"/>'; |
| 169 |
} |
| 170 |
} |
| 171 |
echo "</div>\n"; |
| 172 |
echo '<div class="result" id="deviantart-result"> </div>'; |
| 173 |
} |
| 174 |
|
| 175 |
private function show_token_section($auth, $provider_slug, $provider_text) { |
| 176 |
$this->show_token_section_header($auth, $provider_text); |
| 177 |
if (!empty($auth['api_key']) && !empty($auth['api_secret'])) { |
| 178 |
$this->show_token_section_body($auth, $provider_slug, $provider_text); |
| 179 |
} |
| 180 |
else { |
| 181 |
echo '<div class="result" id="' . esc_attr($provider_slug) . '-result"> </div>'; |
| 182 |
} |
| 183 |
} |
| 184 |
|
| 185 |
/** |
| 186 |
* @param $auth array |
| 187 |
* @param $provider string |
| 188 |
*/ |
| 189 |
private function show_token_section_header(array $auth, string $provider): void { |
| 190 |
echo "<div class=\"photonic-token-header\">\n"; |
| 191 |
|
| 192 |
if ('Instagram' === $provider) { |
| 193 |
echo '<p class="notice notice-error">' . esc_html__("Unfortunately Instagram is no longer supported in Photonic. This is due to a change in Meta's Terms and Conditions, that only allow businesses to access their API. As Photonic is developed by an individual, the API is no longer accessible to the developer.", 'photonic') . '</p><br/>'; |
| 194 |
} |
| 195 |
elseif (empty($auth['api_key']) || empty($auth['api_secret'])) { |
| 196 |
/* Translators: 1: Platform 2: Menu location */ |
| 197 |
echo sprintf(esc_html__('Please set up your %1$s API key under %2$s.', 'photonic'), esc_html($provider), sprintf('<em>Photonic → Settings → %1$s → %1$s Settings</em>', esc_html($provider))); |
| 198 |
} |
| 199 |
elseif ('Instagram' === $provider && !empty($auth['token'])) { |
| 200 |
require_once PHOTONIC_PATH . '/Platforms/Instagram.php'; |
| 201 |
$module = Instagram::get_instance(); |
| 202 |
$expiring_soon = $module->is_token_expiring_soon(30); |
| 203 |
if (is_null($expiring_soon)) { |
| 204 |
// Not yet authenticated with the new API. |
| 205 |
echo '<p class="notice notice-error">' . esc_html__('Your authentication credentials are for the old Instagram API. Please reauthenticate to keep Photonic working.', 'photonic') . '</p><br/>'; |
| 206 |
} |
| 207 |
elseif (1 === $expiring_soon) { |
| 208 |
echo '<p class="notice notice-warning">' . esc_html__('Your authentication credentials are expiring soon. Please reauthenticate to keep Photonic working.', 'photonic') . '</p><br/>'; |
| 209 |
} |
| 210 |
elseif (-1 === $expiring_soon) { |
| 211 |
echo '<p class="notice notice-error">' . esc_html__('Your authentication credentials have expired! Please reauthenticate to keep Photonic working.', 'photonic') . '</p><br/>'; |
| 212 |
} |
| 213 |
else { |
| 214 |
$cached_token = $module->get_cached_token(); |
| 215 |
|
| 216 |
if (!empty($cached_token) && !empty($cached_token['user'])) { |
| 217 |
/* Translators: 1: User in <code> tags */ |
| 218 |
$this->print_auth_done_all_good(sprintf(esc_html__('You are logged in as %1$s.', 'photonic'), '<code>' . $cached_token['user'] . '</code>')); |
| 219 |
} |
| 220 |
else { |
| 221 |
$this->print_auth_done_all_good(); |
| 222 |
} |
| 223 |
} |
| 224 |
} |
| 225 |
elseif (!empty($auth['token'])) { |
| 226 |
$this->print_auth_done_all_good(); |
| 227 |
} |
| 228 |
echo "</div>\n"; |
| 229 |
} |
| 230 |
|
| 231 |
/** |
| 232 |
* @param $auth |
| 233 |
* @param $provider |
| 234 |
* @param $provider_text |
| 235 |
*/ |
| 236 |
public function show_token_section_body($auth, $provider, $provider_text) { |
| 237 |
$photonic_authentication = get_option('photonic_authentication'); |
| 238 |
$response = Base::parse_parameters($_SERVER['QUERY_STRING'] ?? ''); |
| 239 |
|
| 240 |
if (empty($response['provider']) || (!empty($response['provider']) && $provider !== $response['provider'])) { |
| 241 |
$nonce = wp_create_nonce($provider . '-request-token-' . $auth['api_secret']); |
| 242 |
echo "<a href='#' class='button button-primary photonic-token-request' data-photonic-provider='" . esc_attr($provider) . "' data-photonic-nonce='" . esc_attr($nonce) . "'>" . wp_kses_post($this->get_login_button($provider_text)) . '</a>'; |
| 243 |
} |
| 244 |
elseif (!empty($response['oauth_token']) && !empty($response['oauth_verifier'])) { |
| 245 |
if (in_array($provider, ['flickr', 'smug', 'smugmug'], true)) { |
| 246 |
if ('flickr' === $provider) { |
| 247 |
require_once PHOTONIC_PATH . '/Platforms/Flickr.php'; |
| 248 |
$module = Flickr::get_instance(); |
| 249 |
} |
| 250 |
else { |
| 251 |
require_once PHOTONIC_PATH . '/Platforms/SmugMug.php'; |
| 252 |
$module = SmugMug::get_instance(); |
| 253 |
} |
| 254 |
echo "<span class='button photonic-helper-button-disabled'>" . wp_kses_post($this->get_login_button($provider_text)) . '</span>'; |
| 255 |
$authorization = ['oauth_token' => $response['oauth_token'], 'oauth_verifier' => $response['oauth_verifier']]; |
| 256 |
if (isset($photonic_authentication) && isset($photonic_authentication[$provider]) && isset($photonic_authentication[$provider]['oauth_token_secret'])) { |
| 257 |
$authorization['oauth_token_secret'] = $photonic_authentication[$provider]['oauth_token_secret']; |
| 258 |
} |
| 259 |
$access_token = $module->get_access_token($authorization); |
| 260 |
if (isset($access_token['oauth_token'])) { |
| 261 |
echo '<div class="result">Access Token: <code id="' . esc_attr($provider) . '-token">' . esc_html($access_token['oauth_token']) . '</code><br/>Access Token Secret: <code id="' . esc_attr($provider) . '-token-secret">' . esc_html($access_token['oauth_token_secret']) . '</code></div>' . "\n"; |
| 262 |
$nonce = wp_create_nonce($provider . '-save-token-' . $access_token['oauth_token']); |
| 263 |
echo "<a href='#' class='button button-primary photonic-save-token' data-photonic-provider='" . esc_attr($provider) . "' data-photonic-nonce='" . esc_attr($nonce) . "'>" . esc_html__('Save Token', 'photonic') . '</a>'; |
| 264 |
} |
| 265 |
} |
| 266 |
} |
| 267 |
} |
| 268 |
|
| 269 |
private function print_auth_done_all_good($additional_msg = null) { |
| 270 |
echo '<p class="notice notice-success">'; |
| 271 |
esc_html_e('You have already set up your authentication. Unless you wish to regenerate the token this step is not required. ', 'photonic'); |
| 272 |
if (!empty($additional_msg)) { |
| 273 |
echo esc_html($additional_msg); |
| 274 |
} |
| 275 |
echo '</p>'; |
| 276 |
} |
| 277 |
|
| 278 |
private function get_login_button($provider) { |
| 279 |
/* Translators: 1: Platform, untranslated */ |
| 280 |
return sprintf(esc_html__('Login and get Access Token from %s', 'photonic'), $provider); |
| 281 |
} |
| 282 |
|
| 283 |
private function show_token_deletion_button($provider) { |
| 284 |
// echo "<a href='#' class='button button-primary photonic-" . strtolower($provider) . "-delete'>" . esc_html__(sprintf('Delete current %s authentication data', $provider), 'photonic') . '</a>'; |
| 285 |
} |
| 286 |
|
| 287 |
public function obtain_token() { |
| 288 |
$provider = sanitize_text_field($_POST['provider'] ?? ''); |
| 289 |
global $photonic_flickr_api_secret, $photonic_smug_api_secret, $photonic_deviantart_client_secret; |
| 290 |
if ('flickr' === $provider && check_ajax_referer('flickr-request-token-' . $photonic_flickr_api_secret, '_ajax_nonce')) { |
| 291 |
require_once PHOTONIC_PATH . '/Platforms/Flickr.php'; |
| 292 |
$module = Flickr::get_instance(); |
| 293 |
if (empty($_POST['oauth_token']) && empty($_POST['oauth_verifier'])) { |
| 294 |
$request_token = $module->get_request_token(admin_url('admin.php?page=photonic-auth&provider=flickr')); |
| 295 |
$authorize_url = $module->get_authorize_URL($request_token); |
| 296 |
$authorize_url .= '&perms=read'; |
| 297 |
$module->save_token($request_token); |
| 298 |
echo esc_url_raw($authorize_url); |
| 299 |
} |
| 300 |
} |
| 301 |
elseif ('smug' === $provider && check_ajax_referer('smug-request-token-' . $photonic_smug_api_secret, '_ajax_nonce')) { |
| 302 |
require_once PHOTONIC_PATH . '/Platforms/SmugMug.php'; |
| 303 |
$module = SmugMug::get_instance(); |
| 304 |
if (empty($_POST['oauth_token']) && empty($_POST['oauth_verifier'])) { |
| 305 |
$request_token = $module->get_request_token(admin_url('admin.php?page=photonic-auth&provider=smug')); |
| 306 |
$authorize_url = $module->get_authorize_URL($request_token); |
| 307 |
$authorize_url .= '&Access=Full&Permissions=Read'; |
| 308 |
$module->save_token($request_token); |
| 309 |
echo esc_url_raw($authorize_url); |
| 310 |
} |
| 311 |
} |
| 312 |
elseif ('zenfolio' === $provider) { |
| 313 |
$module = Zenfolio::get_instance(); |
| 314 |
if (!empty($_POST['password'])) { |
| 315 |
$response = $module->authenticate($_POST['password']); |
| 316 |
if (!empty($response['error'])) { |
| 317 |
echo wp_kses_post($response['error']); |
| 318 |
} |
| 319 |
elseif (!empty($response['success'])) { |
| 320 |
esc_html_e('Authentication successful! All your galleries will be displayed with Authentication in place.', 'photonic'); |
| 321 |
} |
| 322 |
} |
| 323 |
} |
| 324 |
elseif ('deviantart' === $provider && check_ajax_referer('deviantart-obtain-token-' . $photonic_deviantart_client_secret, '_ajax_nonce')) { |
| 325 |
$code = sanitize_text_field($_POST['code'] ?? ''); |
| 326 |
require_once PHOTONIC_PATH . '/Platforms/DeviantArt.php'; |
| 327 |
$module = DeviantArt::get_instance(); |
| 328 |
$response = Photonic::http( |
| 329 |
$module->access_token_URL(), |
| 330 |
'POST', |
| 331 |
[ |
| 332 |
'code' => $code, |
| 333 |
'grant_type' => 'authorization_code', |
| 334 |
'client_id' => $module->client_id, |
| 335 |
'client_secret' => $module->client_secret, |
| 336 |
'redirect_uri' => admin_url('admin.php?page=photonic-auth&source=deviantart'), |
| 337 |
] |
| 338 |
); |
| 339 |
|
| 340 |
if (!is_wp_error($response) && is_array($response)) { |
| 341 |
$body = json_decode($response['body']); |
| 342 |
// Add nonce to the response. This will be used to save the information in the options. |
| 343 |
$body->nonce = wp_create_nonce('deviantart-save-token-' . $body->refresh_token); |
| 344 |
echo(wp_json_encode($body)); |
| 345 |
} |
| 346 |
} |
| 347 |
} |
| 348 |
|
| 349 |
public function delete_token_from_options() { |
| 350 |
if (isset($_POST['provider']) && check_ajax_referer($_POST['provider'] . '-delete-token')) { |
| 351 |
$provider = strtolower(sanitize_text_field($_POST['provider'])); |
| 352 |
if (in_array($provider, ['flickr', 'smug', 'zenfolio', 'google', 'instagram'], true) && current_user_can('edit_theme_options')) { |
| 353 |
$photonic_authentication = get_option('photonic_authentication'); |
| 354 |
if ('zenfolio' === $provider) { |
| 355 |
if (isset($photonic_authentication[$provider])) { |
| 356 |
unset($photonic_authentication[$provider]); |
| 357 |
} |
| 358 |
} |
| 359 |
update_option('photonic_authentication', $photonic_authentication); |
| 360 |
} |
| 361 |
} |
| 362 |
die(); |
| 363 |
} |
| 364 |
} |
| 365 |
|