diff --git a/composer.json b/composer.json index 196f5a9..a7dbea7 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ "indieweb/date-formatter": "0.1.*", "indieauth/client": "0.1.3", "mpratt/relativetime": ">=1.0", - "firebase/php-jwt": "dev-master" + "firebase/php-jwt": "dev-master", + "ruudk/twitter-oauth": "dev-master" }, "autoload": { "files": [ diff --git a/composer.lock b/composer.lock index a4e4ad6..0bdac28 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "3e034e0a6a692d5bbfecfdc95ee69db2", + "hash": "502847c033f5a54c69a6a1a51d26e894", "packages": [ { "name": "firebase/php-jwt", @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "53669d621149e49c2a428722a62acfef3342c260" + "reference": "83b8899cb73d85d648af93f37ec0ac89f4a5bbae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/53669d621149e49c2a428722a62acfef3342c260", - "reference": "53669d621149e49c2a428722a62acfef3342c260", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b8899cb73d85d648af93f37ec0ac89f4a5bbae", + "reference": "83b8899cb73d85d648af93f37ec0ac89f4a5bbae", "shasum": "" }, "require": { @@ -26,7 +26,8 @@ "type": "library", "autoload": { "classmap": [ - "Authentication/" + "Authentication/", + "Exceptions/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -47,7 +48,7 @@ ], "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", "homepage": "https://github.com/firebase/php-jwt", - "time": "2013-09-03 20:55:18" + "time": "2014-11-18 17:58:25" }, { "name": "indieauth/client", @@ -367,6 +368,41 @@ ], "time": "2013-09-23 22:51:48" }, + { + "name": "ruudk/twitter-oauth", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/ruudk/twitteroauth.git", + "reference": "7f5a94eaa1572ddbc7f0a32ba3b865b8ac23712a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ruudk/twitteroauth/zipball/7f5a94eaa1572ddbc7f0a32ba3b865b8ac23712a", + "reference": "7f5a94eaa1572ddbc7f0a32ba3b865b8ac23712a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "authors": [ + { + "name": "Ruud Kamphuis", + "email": "ruud@1plus1media.nl", + "role": "Developer" + } + ], + "description": "PHP 5.3 version of abraham/twitteroauth", + "homepage": "http://github.com/ruudk/twitteroauth", + "time": "2014-06-10 18:17:38" + }, { "name": "saltybeagle/savant3", "version": "dev-master", @@ -446,21 +482,14 @@ "time": "2012-12-13 02:15:50" } ], - "packages-dev": [ - - ], - "aliases": [ - - ], + "packages-dev": [], + "aliases": [], "minimum-stability": "stable", "stability-flags": { "saltybeagle/savant3": 20, - "firebase/php-jwt": 20 + "firebase/php-jwt": 20, + "ruudk/twitter-oauth": 20 }, - "platform": [ - - ], - "platform-dev": [ - - ] + "platform": [], + "platform-dev": [] } diff --git a/controllers/controllers.php b/controllers/controllers.php index 0de366b..18da149 100644 --- a/controllers/controllers.php +++ b/controllers/controllers.php @@ -1,6 +1,6 @@ request()->params(); if(array_key_exists('token', $params)) { try { @@ -8,16 +8,25 @@ function require_login(&$app) { $_SESSION['user_id'] = $data->user_id; $_SESSION['me'] = $data->me; } catch(DomainException $e) { - header('X-Error: DomainException'); - $app->redirect('/', 301); + if($redirect) { + header('X-Error: DomainException'); + $app->redirect('/', 301); + } else { + return false; + } } catch(UnexpectedValueException $e) { - header('X-Error: UnexpectedValueException'); - $app->redirect('/', 301); + if($redirect) { + header('X-Error: UnexpectedValueException'); + $app->redirect('/', 301); + } else { + return false; + } } } if(!array_key_exists('user_id', $_SESSION)) { - $app->redirect('/'); + if($redirect) + $app->redirect('/'); return false; } else { return ORM::for_table('users')->find_one($_SESSION['user_id']); @@ -160,6 +169,42 @@ $app->get('/add-to-home', function() use($app) { } }); +$app->get('/settings', function() use($app) { + if($user=require_login($app)) { + $html = render('settings', array('title' => 'Settings', 'include_facebook' => true)); + $app->response()->body($html); + } +}); + +$app->get('/favorite.js', function() use($app) { + $app->response()->header("Content-type", "text/javascript"); + if($user=require_login($app, false)) { + $params = $app->request()->params(); + + if(array_key_exists('url', $params)) { + $micropub_request = array( + 'like-of' => $params['url'] + ); + $r = micropub_post_for_user($user, $micropub_request); + } + + if(preg_match('/https?:\/\/(?:www\.)?facebook\.com\/(?:[^\/]+)\/posts\/(\d+)/', $params['url'], $match)) { + $facebook_id = $match[1]; + } else { + $facebook_id = false; + } + + $app->response()->body($app->render('liked-js.php', array( + 'url' => $params['url'], + 'like_url' => $r['location'], + 'error' => $r['error'], + 'facebook_id' => $facebook_id + ))); + } else { + $app->response()->body('alert("invalid token");'); + } +}); + $app->get('/micropub/syndications', function() use($app) { if($user=require_login($app)) { $data = get_syndication_targets($user); @@ -179,31 +224,112 @@ $app->post('/micropub/post', function() use($app) { return $v !== ''; }); - // Now send to the micropub endpoint - $r = micropub_post($user->micropub_endpoint, $params, $user->micropub_access_token); - $request = $r['request']; - $response = $r['response']; + $r = micropub_post_for_user($user, $params); + + $app->response()->body(json_encode(array( + 'request' => htmlspecialchars($r['request']), + 'response' => htmlspecialchars($r['response']), + 'location' => $r['location'], + 'error' => $r['error'], + 'curlinfo' => $r['curlinfo'] + ))); + } +}); + +$app->post('/auth/facebook', function() use($app) { + if($user=require_login($app, false)) { + $params = $app->request()->params(); + // User just auth'd with facebook, store the access token + $user->facebook_access_token = $params['fb_token']; + $user->save(); + + $app->response()->body(json_encode(array( + 'result' => 'ok' + ))); + } else { + $app->response()->body(json_encode(array( + 'result' => 'error' + ))); + } +}); + +$app->post('/auth/twitter', function() use($app) { + if($user=require_login($app, false)) { + $params = $app->request()->params(); + // User just auth'd with facebook, store the access token + $user->twitter_access_token = $params['twitter_token']; + $user->twitter_token_secret = $params['twitter_secret']; + $user->save(); + + $app->response()->body(json_encode(array( + 'result' => 'ok' + ))); + } else { + $app->response()->body(json_encode(array( + 'result' => 'error' + ))); + } +}); + +function getTwitterLoginURL(&$twitter) { + $request_token = $twitter->getRequestToken(Config::$base_url . 'auth/twitter/callback'); + $_SESSION['twitter_auth'] = $request_token; + return $twitter->getAuthorizeURL($request_token['oauth_token']); +} + +$app->get('/auth/twitter', function() use($app) { + $params = $app->request()->params(); + if($user=require_login($app, false)) { - $user->last_micropub_response = json_encode($r); - $user->last_micropub_response_date = date('Y-m-d H:i:s'); + // If there is an existing Twitter token, check if it is valid + // Otherwise, generate a Twitter login link + $twitter_login_url = false; + $twitter = new \TwitterOAuth\Api(Config::$twitterClientID, Config::$twitterClientSecret, + $user->twitter_access_token, $user->twitter_token_secret); - // Check the response and look for a "Location" header containing the URL - if($response && preg_match('/Location: (.+)/', $response, $match)) { - $location = $match[1]; - $user->micropub_success = 1; + if(array_key_exists('login', $params)) { + $twitter = new \TwitterOAuth\Api(Config::$twitterClientID, Config::$twitterClientSecret); + $twitter_login_url = getTwitterLoginURL($twitter); } else { - $location = false; + if($user->twitter_access_token) { + if ($twitter->get('account/verify_credentials')) { + $app->response()->body(json_encode(array( + 'result' => 'ok' + ))); + return; + } else { + // If the existing twitter token is not valid, generate a login link + $twitter_login_url = getTwitterLoginURL($twitter); + } + } else { + $twitter_login_url = getTwitterLoginURL($twitter); + } } - $user->save(); + $app->response()->body(json_encode(array( + 'url' => $twitter_login_url + ))); + } else { $app->response()->body(json_encode(array( - 'request' => htmlspecialchars($request), - 'response' => htmlspecialchars($response), - 'location' => $location, - 'error' => $r['error'], - 'curlinfo' => $r['curlinfo'] + 'result' => 'error' ))); } }); +$app->get('/auth/twitter/callback', function() use($app) { + if($user=require_login($app)) { + $params = $app->request()->params(); + + $twitter = new \TwitterOAuth\Api(Config::$twitterClientID, Config::$twitterClientSecret, + $_SESSION['twitter_auth']['oauth_token'], $_SESSION['twitter_auth']['oauth_token_secret']); + $credentials = $twitter->getAccessToken($params['oauth_verifier']); + + $user->twitter_access_token = $credentials['oauth_token']; + $user->twitter_token_secret = $credentials['oauth_token_secret']; + $user->twitter_username = $credentials['screen_name']; + $user->save(); + + $app->redirect('/settings'); + } +}); diff --git a/lib/config.template.php b/lib/config.template.php index df80efa..dae8968 100644 --- a/lib/config.template.php +++ b/lib/config.template.php @@ -10,5 +10,12 @@ class Config { public static $dbPassword = ''; public static $jwtSecret = 'xxx'; + + public static $fbClientID = ''; + public static $fbClientSecret = ''; + public static $twitterClientID = ''; + public static $twitterClientSecret = ''; + public static $instagramClientID = ''; + public static $instagramClientSecret = ''; } diff --git a/lib/helpers.php b/lib/helpers.php index cf751c6..010bd91 100644 --- a/lib/helpers.php +++ b/lib/helpers.php @@ -70,6 +70,26 @@ function get_timezone($lat, $lng) { return null; } +function micropub_post_for_user(&$user, $params) { + // Now send to the micropub endpoint + $r = micropub_post($user->micropub_endpoint, $params, $user->micropub_access_token); + + $user->last_micropub_response = json_encode($r); + $user->last_micropub_response_date = date('Y-m-d H:i:s'); + + // Check the response and look for a "Location" header containing the URL + if($r['response'] && preg_match('/Location: (.+)/', $r['response'], $match)) { + $r['location'] = $match[1]; + $user->micropub_success = 1; + } else { + $r['location'] = false; + } + + $user->save(); + + return $r; +} + function micropub_post($endpoint, $params, $access_token) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $endpoint); diff --git a/public/css/favorite.css b/public/css/favorite.css new file mode 100644 index 0000000..a80bc3a --- /dev/null +++ b/public/css/favorite.css @@ -0,0 +1,17 @@ + +#quill-star { + position: absolute; + + top: 50%; + left: 50%; + margin-top: -100px; + margin-left: -100px; + + width: 200px; + height: 200px; + +} + +#quill-star.hidden { + display: none; +} diff --git a/public/images/quill-logo-1024.png b/public/images/quill-logo-1024.png new file mode 100644 index 0000000..b6bc513 Binary files /dev/null and b/public/images/quill-logo-1024.png differ diff --git a/public/images/red-x.svg b/public/images/red-x.svg new file mode 100644 index 0000000..041364d --- /dev/null +++ b/public/images/red-x.svg @@ -0,0 +1,8 @@ + + + + diff --git a/public/images/star.svg b/public/images/star.svg new file mode 100644 index 0000000..5970e33 --- /dev/null +++ b/public/images/star.svg @@ -0,0 +1,8 @@ + + + + diff --git a/public/js/fav.js b/public/js/fav.js new file mode 100644 index 0000000..4288329 --- /dev/null +++ b/public/js/fav.js @@ -0,0 +1,23 @@ +console.log("Favoriting with token: " + quill_token); + +var http = new XMLHttpRequest(); +var params = "like-of=" + encodeURIComponent(window.location) + "&token=" + quill_token; + +http.open("POST", "http://quill.dev/favorite", true); +http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + +http.onreadystatechange = function() {//Call a function when the state changes. + console.log(http); + if(http.readyState == 4 && http.status == 200) { + alert(http.responseText); + } +} +http.send(params); + +/* + +(function(){var el=document.createElement('input'); el.type="hidden"; el.id="quill_token"; el.value="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMjciLCJtZSI6Imh0dHA6XC9cL2Fhcm9ucGFyZWNraS5jb20iLCJjcmVhdGVkX2F0IjoxNDEwMTE3NTM5fQ.ifp1VIgCTz9NPtMTlTLPBXAGSxHwpGS5tLPhXGxrjNk"; document.body.appendChild(el); document.body.appendChild(document.createElement('script')).src='http://quill.dev/js/fav.js';})(); + +(function(){document.body.appendChild(document.createElement('script')).src='http://quill.dev/favorite.js?url='+encodeURIComponent(window.location)+'&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMSIsIm1lIjoiaHR0cDpcL1wvcGsuZGV2XC8iLCJjcmVhdGVkX2F0IjoxNDE5MDM2NzAzfQ.AgJ5xyviiBzWOvQO0je0Bdi3BUpKJ4CLJnx8GIm-0OI';})(); + +*/ \ No newline at end of file diff --git a/views/layout.php b/views/layout.php index 531dec9..0c78aa7 100644 --- a/views/layout.php +++ b/views/layout.php @@ -31,6 +31,12 @@
+ + \ No newline at end of file diff --git a/views/settings.php b/views/settings.php new file mode 100644 index 0000000..61feefc --- /dev/null +++ b/views/settings.php @@ -0,0 +1,88 @@ += session('me') ?>
+
+