| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 | 
							- <?php
 
- /**
 
-  * A Service is a remote site/service/system for which Keyring is capable of managing
 
-  * authentication. Each Service should have a series of methods for handling the creation
 
-  * of an authentication token, verifying the token and for performing authenticated
 
-  * requests.
 
-  *
 
-  * @package Keyring
 
-  */
 
- abstract class Keyring_Service {
 
- 	const NAME          = '';
 
- 	const LABEL         = '';
 
- 	protected $token          = false;
 
- 	protected $requires_token = true;
 
- 	protected $store          = false;
 
- 	private   $request_response_code = '';
 
- 	/**
 
- 	 * Handle the first part of getting a Token for this Service. In some cases
 
- 	 * this may involve UI, in others it might just be a redirect.
 
- 	 */
 
- 	abstract function request_token();
 
- 	/**
 
- 	 * Second step/verification of a Token. This is where you can make a
 
- 	 * test request, load meta, whatever you need to do. MUST include a call
 
- 	 * to ::verified() at the end, if the Token is successfully verified.
 
- 	 *
 
- 	 * @return void
 
- 	 * @author Beau Lebens
 
- 	 */
 
- 	abstract function verify_token();
 
- 	/**
 
- 	 * Make an outbound request against this Service, using the current Token
 
- 	 * if ->requires_token() return true.
 
- 	 *
 
- 	 * @param string $url The URL to make the request against
 
- 	 * @param array $params Additional parameters for the request (a la WP_HTTP)
 
- 	 * @return String containing the body of the response on success, or Keyring_Error on any non-200 response
 
- 	 */
 
- 	abstract function request( $url, array $params );
 
- 	/**
 
- 	 * Get a displayable string for the passed token, for this service
 
- 	 *
 
- 	 * @param obj $token Keyring_Access_Token object
 
- 	 * @return String for display, describing $token
 
- 	 */
 
- 	abstract function get_display( Keyring_Access_Token $token );
 
- 	/**
 
- 	 * Get an array of meta data to store with this token, based on parsing the access token
 
- 	 * details passed back from the remote service.
 
- 	 *
 
- 	 * @param Mixed $token
 
- 	 * @return Array containing keyed values to store along with this token
 
- 	 */
 
- 	function build_token_meta( $token ) {
 
- 		return apply_filters( 'keyring_access_token_meta', array(), $this->get_name(), $token, null, $this );
 
- 	}
 
- 	function __construct() {
 
- 		$this->store = Keyring::get_token_store();
 
- 		// Default methods for handling actions, should always be defined (thus abstract, see above)
 
- 		add_action( 'keyring_' . $this->get_name() . '_request', array( $this, 'request_token' ) );
 
- 		add_action( 'keyring_' . $this->get_name() . '_verify', array( $this, 'verify_token' ) );
 
- 	}
 
- 	static function &init() {
 
- 		static $instance = false;
 
- 		if ( !$instance ) {
 
- 			$class = get_called_class();
 
- 			$services = Keyring::get_registered_services();
 
- 			if ( in_array( $class::NAME, array_keys( $services ) ) ) {
 
- 				$instance = $services[ $class::NAME ];
 
- 			} else {
 
- 				$instance = new $class;
 
- 				Keyring::register_service( $instance );
 
- 			}
 
- 		}
 
- 		return $instance;
 
- 	}
 
- 	/**
 
- 	 * Get/set whether this Service requires a token before making requests.
 
- 	 *
 
- 	 * @param boolean $does_it
 
- 	 * @return True if token is required, false if not. If called with no
 
- 	 *         param, then just returns true/false. If called with a bool,
 
- 	 *         then set requirement to true/false as specified.
 
- 	 */
 
- 	function requires_token( $does_it = null ) {
 
- 		if ( is_null( $does_it ) )
 
- 			return $this->requires_token;
 
- 		$requires = $this->requires_token;
 
- 		$this->requires_token = $does_it;
 
- 		return $requires;
 
- 	}
 
- 	function get_name() {
 
- 		$c = get_called_class();
 
- 		if ( '' != $c::NAME )
 
- 			$name = $c::NAME;
 
- 		else
 
- 			$name = strtolower( $c );
 
- 		return $name;
 
- 	}
 
- 	function get_label() {
 
- 		$c = get_called_class();
 
- 		if ( '' != $c::LABEL )
 
- 			$label = $c::LABEL;
 
- 		else
 
- 			$label = $this->get_name();
 
- 		return $label;
 
- 	}
 
- 	function set_endpoint( $type, $url, $method = 'GET' ) {
 
- 		$this->{$type . '_url'}    = $url;
 
- 		$this->{$type . '_method'} = strtoupper( $method );
 
- 		return true;
 
- 	}
 
- 	function get_request_response_code() {
 
- 		return $this->request_response_code;
 
- 	}
 
- 	function set_request_response_code( $code ) {
 
- 		$this->request_response_code = $code;
 
- 	}
 
- 	function basic_ui() {
 
- 		if ( !isset( $_REQUEST['nonce'] ) || !wp_verify_nonce( $_REQUEST['nonce'], 'keyring-manage-' . $this->get_name() ) ) {
 
- 			Keyring::error( __( 'Invalid/missing management nonce.', 'keyring' ) );
 
- 			exit;
 
- 		}
 
- 		// Common Header
 
- 		echo '<div class="wrap">';
 
- 		screen_icon( 'ms-admin' );
 
- 		echo '<h2>' . __( 'Keyring Service Management', 'keyring' ) . '</h2>';
 
- 		echo '<p><a href="' . Keyring_Util::admin_url( false, array( 'action' => 'services' ) ) . '">' . __( '← Back', 'keyring' ) . '</a></p>';
 
- 		echo '<h3>' . sprintf( __( '%s API Credentials', 'keyring' ), esc_html( $this->get_label() ) ) . '</h3>';
 
- 		// Handle actually saving credentials
 
- 		if ( isset( $_POST['api_key'] ) && isset( $_POST['api_secret'] ) ) {
 
- 			// Store credentials against this service
 
- 			$this->update_credentials( array(
 
- 				'app_id' => stripslashes( $_POST['app_id'] ),
 
- 				'key'    => stripslashes( $_POST['api_key'] ),
 
- 				'secret' => stripslashes( $_POST['api_secret'] )
 
- 			) );
 
- 			echo '<div class="updated"><p>' . __( 'Credentials saved.', 'keyring' ) . '</p></div>';
 
- 		}
 
- 		$app_id = $api_key = $api_secret = '';
 
- 		if ( $creds = $this->get_credentials() ) {
 
- 			$app_id     = $creds['app_id'];
 
- 			$api_key    = $creds['key'];
 
- 			$api_secret = $creds['secret'];
 
- 		}
 
- 		echo apply_filters( 'keyring_' . $this->get_name() . '_basic_ui_intro', '' );
 
- 		// Output basic form for collecting key/secret
 
- 		echo '<form method="post" action="">';
 
- 		echo '<input type="hidden" name="service" value="' . esc_attr( $this->get_name() ) . '" />';
 
- 		echo '<input type="hidden" name="action" value="manage" />';
 
- 		wp_nonce_field( 'keyring-manage', 'kr_nonce', false );
 
- 		wp_nonce_field( 'keyring-manage-' . $this->get_name(), 'nonce', false );
 
- 		echo '<table class="form-table">';
 
- 		echo '<tr><th scope="row">' . __( 'App ID', 'keyring' ) . '</th>';
 
- 		echo '<td><input type="text" name="app_id" value="' . esc_attr( $app_id ) . '" id="app_id" class="regular-text"></td></tr>';
 
- 		echo '<tr><th scope="row">' . __( 'API Key', 'keyring' ) . '</th>';
 
- 		echo '<td><input type="text" name="api_key" value="' . esc_attr( $api_key ) . '" id="api_key" class="regular-text"></td></tr>';
 
- 		echo '<tr><th scope="row">' . __( 'API Secret', 'keyring' ) . '</th>';
 
- 		echo '<td><input type="text" name="api_secret" value="' . esc_attr( $api_secret ) . '" id="api_secret" class="regular-text"></td></tr>';
 
- 		echo '</table>';
 
- 		echo '<p class="submitbox">';
 
- 		echo '<input type="submit" name="submit" value="' . __( 'Save Changes', 'keyring' ) . '" id="submit" class="button-primary">';
 
- 		echo '<a href="' . esc_url( $_SERVER['HTTP_REFERER'] ) . '" class="submitdelete" style="margin-left:2em;">' . __( 'Cancel', 'keyring' ) . '</a>';
 
- 		echo '</p>';
 
- 		echo '</form>';
 
- 		?><script type="text/javascript" charset="utf-8">
 
- 			jQuery( document ).ready( function() {
 
- 				jQuery( '#app_id' ).focus();
 
- 			} );
 
- 		</script><?php
 
- 		echo '</div>';
 
- 	}
 
- 	/**
 
- 	 * Return any stored credentials for this service, or false if none.
 
- 	 *
 
- 	 * @return Array containing credentials or false if none
 
- 	 */
 
- 	function get_credentials() {
 
- 		// First attempt custom credentials for this service
 
- 		// Return null from _get_credentials() to allow falling through to the other checks below
 
- 		// Return false if the service requires no configuration
 
- 		if ( method_exists( $this, '_get_credentials' ) ) {
 
- 			$creds = $this->_get_credentials();
 
- 			if ( !is_null( $creds ) )
 
- 				return apply_filters( 'keyring_service_credentials', $creds, $this->get_name() );
 
- 		}
 
- 		// Then check for generic constants
 
- 		$name = $this->get_name();
 
- 		$name = strtoupper( preg_replace( '/[^a-zA-Z0-9]/', '', $name ) ); // Remove all non alpha-numeric chars from name
 
- 		if (
 
- 			defined( 'KEYRING__' . $name . '_ID' )
 
- 		&&
 
- 			defined( 'KEYRING__' . $name . '_KEY' )
 
- 		&&
 
- 			defined( 'KEYRING__' . $name . '_SECRET' )
 
- 		) {
 
- 			$creds = array(
 
- 				'app_id' => constant( 'KEYRING__' . $name . '_ID' ),
 
- 				'key'    => constant( 'KEYRING__' . $name . '_KEY' ),
 
- 				'secret' => constant( 'KEYRING__' . $name . '_SECRET' ),
 
- 			);
 
- 			return apply_filters( 'keyring_service_credentials', $creds, $this->get_name() );
 
- 		}
 
- 		// Last check in the database for a shared store of credentials
 
- 		$creds = false;
 
- 		$all   = apply_filters( 'keyring_credentials', get_option( 'keyring_credentials' ) );
 
- 		if ( !empty( $all[ $this->get_name() ] ) ) {
 
- 			$creds = $all[ $this->get_name() ];
 
- 		}
 
- 		return apply_filters( 'keyring_service_credentials', $creds, $this->get_name() );
 
- 	}
 
- 	/**
 
- 	 * Update stored credentials for this service. Accept an array and just
 
- 	 * store it in a serialized array, keyed off the name of the service.
 
- 	 *
 
- 	 * @param array $credentials
 
- 	 */
 
- 	function update_credentials( array $credentials ) {
 
- 		$all = apply_filters( 'keyring_credentials', get_option( 'keyring_credentials' ) );
 
- 		$all[ $this->get_name() ] = $credentials;
 
- 		return update_option( 'keyring_credentials', $all );
 
- 	}
 
- 	/**
 
- 	 * If a service requires some sort of configuration before it can be used (e.g. specifying a key/secret),
 
- 	 * then this method allows you to confirm that that configuration has taken place before attempting to
 
- 	 * use it. You can use it to ::get_credentials() or something and make sure they look valid for example.
 
- 	 * Return a boolean. Default just returns true, meaning "this service is configured correctly and OK to use".
 
- 	 * @return Boolean true if service is configured correctly, false otherwise.
 
- 	 */
 
- 	function is_configured() {
 
- 		return true;
 
- 	}
 
- 	function verified( $id, $request_token = null ) {
 
- 		$c = get_called_class();
 
- 		// If something else needs to be done, do it
 
- 		do_action( 'keyring_connection_verified', $c::NAME, $id, $request_token );
 
- 		// Back to Keyring admin, with ?service=SERVICE&created=UNIQUE_ID&kr_nonce=NONCE
 
- 		$kr_nonce = wp_create_nonce( 'keyring-created' );
 
- 		$url = apply_filters( 'keyring_verified_redirect', Keyring_Util::admin_url( $c::NAME, array( 'action' => 'created', 'id' => $id, 'kr_nonce' => $kr_nonce ) ), $c::NAME );
 
- 		Keyring_Util::debug( 'Verified connection, redirect to ' . $url );
 
- 		wp_safe_redirect( $url );
 
- 		exit;
 
- 	}
 
- 	function is_connected() {
 
- 		$c = get_called_class();
 
- 		return Keyring::get_token_store()->count( array( 'service' => $c::NAME ) );
 
- 	}
 
- 	function store_token( $token ) {
 
- 		$token->meta['_classname'] = get_called_class();
 
- 		$id = $this->store->insert( $token );
 
- 		return $id;
 
- 	}
 
- 	function set_token( Keyring_Access_Token $token ) {
 
- 		$this->token = $token;
 
- 	}
 
- 	/**
 
- 	 * Just returns the currently-set token for this service
 
- 	 * @return [type] [description]
 
- 	 */
 
- 	function get_token() {
 
- 		return $this->token;
 
- 	}
 
- 	function get_tokens( $id = false ) {
 
- 		$c = get_called_class();
 
- 		return $this->store->get_tokens( array( 'service' => $c::NAME, 'type' => 'access' ) );
 
- 	}
 
- 	function token_select_box( $name, $create = false ) {
 
- 		$tokens = $this->get_tokens();
 
- 		return Keyring_Util::token_select_box( $tokens, $name, $create );
 
- 	}
 
- }
 
- // Load all packaged services in the ./includes/services/ directory by including all PHP files, first in core, then in extended
 
- // Remove a Service (prevent it from loading at all) by filtering on 'keyring_services'
 
- $keyring_services = glob( dirname( __FILE__ ) . "/includes/services/core/*.php" );
 
- $keyring_services = array_merge( $keyring_services, glob( dirname( __FILE__ ) . "/includes/services/extended/*.php" ) );
 
- $keyring_services = apply_filters( 'keyring_services', $keyring_services );
 
- foreach ( $keyring_services as $keyring_service )
 
- 	require $keyring_service;
 
- unset( $keyring_services, $keyring_service );
 
 
  |