summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorkurrik@chromium.org <kurrik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-20 23:27:30 +0000
committerkurrik@chromium.org <kurrik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-20 23:27:30 +0000
commit343cd23f33bee4216fcb85baba2d42f08428f48c (patch)
tree7563c903fc211019d4333a113dc87ae3deb12ba1 /chrome
parent0cb5c0cf32a111c7e32bd1fc03398660776d36fe (diff)
downloadchromium_src-343cd23f33bee4216fcb85baba2d42f08428f48c.zip
chromium_src-343cd23f33bee4216fcb85baba2d42f08428f48c.tar.gz
chromium_src-343cd23f33bee4216fcb85baba2d42f08428f48c.tar.bz2
Adding Chrome Web Store PHP Hello World. BUG=None TEST=None
Review URL: http://codereview.chromium.org/3122030 Patch from Eric Bidelman <ericbidelman@chromium.org>. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56936 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/NOTICE97
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/README9
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/index.php289
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/lib/lightopenid/openid.php563
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/CHANGELOG.txt15
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/LICENSE.txt22
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/OAuth.php879
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/main.css90
-rw-r--r--chrome/common/extensions/docs/examples/apps/hello-php/popuplib.js279
9 files changed, 2243 insertions, 0 deletions
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/NOTICE b/chrome/common/extensions/docs/examples/apps/hello-php/NOTICE
new file mode 100644
index 0000000..261a409
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/NOTICE
@@ -0,0 +1,97 @@
+======================================================================
+./popuplib.js (PopupManager):
+======================================================================
+
+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+======================================================================
+./index.php JS templating engine:
+======================================================================
+
+The MIT License
+
+Copyright (c) 2010 John Resig
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+======================================================================
+./lib/oauth/ is licensed as follows
+ (Cf. ../lib/oauth/LICENSE.txt):
+======================================================================
+
+The MIT License
+
+Copyright (c) 2007 Andy Smith
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+======================================================================
+./lib/lightopenid/ is licensed as follows
+ (Cf. ../lib/lightopenid/openid.php):
+======================================================================
+
+The MIT License
+
+Copyright (c) 2010, Mewp
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/README b/chrome/common/extensions/docs/examples/apps/hello-php/README
new file mode 100644
index 0000000..c6566e9
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/README
@@ -0,0 +1,9 @@
+See the documentation at
+ http://code.google.com/chrome/webstore/docs/get_started.html
+for instructions on how to use these files.
+
+"lib" contains the necessary OAuth and OpenID libraries to talk to the Chrome
+Web Store Licensing API and Google's OpenID endpoint.
+
+To "index.php", replace APP_ID, TOKEN, and TOKEN_SECRET with your app's id, your
+developer OAuth access token, and its token secret, respectively.
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/index.php b/chrome/common/extensions/docs/examples/apps/hello-php/index.php
new file mode 100644
index 0000000..f145776
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/index.php
@@ -0,0 +1,289 @@
+<?php
+/**
+ * A "Hello world!" for the Chrome Web Store Licensing API, in PHP. This
+ * program logs the user in with Google's Federated Login API (OpenID), fetches
+ * their license state with OAuth, and prints one of these greetings as
+ * appropriate:
+ *
+ * 1. This user has FREE_TRIAL access to this application ( appId: 1 )
+ * 2. This user has FULL access to this application ( appId: 1 )
+ * 3. This user has NO access to this application ( appId: 1 )
+ *
+ * This code makes use of a popup ui extension to the OpenID protocol. Instead
+ * of the user being redirected to the Google login page, a popup window opens
+ * to the login page, keeping the user on the main application page. See
+ * popuplib.js
+ *
+ * Copyright 2010 the Chromium Authors
+ *
+ * Use of this source code is governed by a BSD-style license that can be found
+ * in the "LICENSE" file.
+ *
+ * Eric Bidelman <ericbidelman@chromium.org>
+ */
+
+session_start();
+
+require_once 'lib/oauth/OAuth.php';
+require_once 'lib/lightopenid/openid.php';
+
+// Full URL of the current application is running under.
+$scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on') ? 'http' :
+ 'https';
+$selfUrl = "$scheme://{$_SERVER['HTTP_HOST']}{$_SERVER['PHP_SELF']}";
+
+
+/**
+ * Wrapper class to make calls to the Chrome Web Store License Server.
+ */
+class LicenseServerClient {
+
+ const LICENSE_SERVER_HOST = 'https://www.googleapis.com';
+ const CONSUMER_KEY = 'anonymous';
+ const CONSUMER_SECRET = 'anonymous';
+ const APP_ID = '1'; // Change to the correct id of your application.
+ const TOKEN = '[REPLACE THIS WITH YOUR OAUTH TOKEN]';
+ const TOKEN_SECRET = '[REPLACE THIS WITH YOUR OAUTH TOKEN SECRET]';
+ public $consumer;
+ public $token;
+ public $signatureMethod;
+
+ public function __construct() {
+ $this->consumer = new OAuthConsumer(
+ self::CONSUMER_KEY, self::CONSUMER_SECRET, NULL);
+ $this->token = new OAuthToken(self::TOKEN, self::TOKEN_SECRET);
+ $this->signatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
+ }
+
+ /**
+ * Makes an HTTP GET request to the specified URL.
+ *
+ * @param string $url Full URL of the resource to access
+ * @param string $request OAuthRequest containing the signed request to make.
+ * @param array $extraHeaders (optional) Array of headers.
+ * @param bool $returnResponseHeaders True if resp headers should be returned.
+ * @return string Response body from the server.
+ */
+ protected function send_signed_get($request, $extraHeaders=NULL,
+ $returnRequestHeaders=false,
+ $returnResponseHeaders=false) {
+ $url = explode('?', $request->to_url());
+ $curl = curl_init($url[0]);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl, CURLOPT_FAILONERROR, false);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+
+ // Return request headers in the response.
+ curl_setopt($curl, CURLINFO_HEADER_OUT, $returnRequestHeaders);
+
+ // Return response headers in the response?
+ if ($returnResponseHeaders) {
+ curl_setopt($curl, CURLOPT_HEADER, true);
+ }
+
+ $headers = array($request->to_header());
+ if (is_array($extraHeaders)) {
+ $headers = array_merge($headers, $extraHeaders);
+ }
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+
+ // Execute the request. If an error occurs fill the response body with it.
+ $response = curl_exec($curl);
+ if (!$response) {
+ $response = curl_error($curl);
+ }
+
+ // Add server's response headers to our response body
+ $response = curl_getinfo($curl, CURLINFO_HEADER_OUT) . $response;
+
+ curl_close($curl);
+
+ return $response;
+ }
+
+ public function checkLicense($userId) {
+ $url = self::LICENSE_SERVER_HOST . '/chromewebstore/v1/licenses/' .
+ self::APP_ID . '/' . urlencode($userId);
+
+ $request = OAuthRequest::from_consumer_and_token(
+ $this->consumer, $this->token, 'GET', $url, array());
+
+ $request->sign_request($this->signatureMethod, $this->consumer,
+ $this->token);
+
+ return $this->send_signed_get($request);
+ }
+}
+
+try {
+ $openid = new LightOpenID();
+ $userId = $openid->identity;
+ if (!isset($_GET['openid_mode'])) {
+ // This section performs the OpenID dance with the normal redirect. Use it
+ // if you want an alternative to the popup UI.
+ if (isset($_GET['login'])) {
+ $openid->identity = 'https://www.google.com/accounts/o8/id';
+ $openid->required = array('namePerson/first', 'namePerson/last',
+ 'contact/email');
+ header('Location: ' . $openid->authUrl());
+ }
+ } else if ($_GET['openid_mode'] == 'cancel') {
+ echo 'User has canceled authentication!';
+ } else {
+ $userId = $openid->validate() ? $openid->identity : '';
+ $_SESSION['userId'] = $userId;
+ $attributes = $openid->getAttributes();
+ $_SESSION['attributes'] = $attributes;
+ }
+} catch(ErrorException $e) {
+ echo $e->getMessage();
+ exit;
+}
+
+if (isset($_REQUEST['popup']) && !isset($_SESSION['redirect_to'])) {
+ $_SESSION['redirect_to'] = $selfUrl;
+ echo '<script type = "text/javascript">window.close();</script>';
+ exit;
+} else if (isset($_SESSION['redirect_to'])) {
+ $redirect = $_SESSION['redirect_to'];
+ unset($_SESSION['redirect_to']);
+ header('Location: ' . $redirect);
+} else if (isset($_REQUEST['queryLicenseServer'])) {
+ $ls = new LicenseServerClient();
+ echo $ls->checkLicense($_REQUEST['user_id']);
+ exit;
+} else if (isset($_GET['logout'])) {
+ unset($_SESSION['attributes']);
+ unset($_SESSION['userId']);
+ header('Location: ' . $selfUrl);
+}
+?>
+
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <link href="main.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="popuplib.js"></script>
+ <script type="text/html" id="ls_tmpl">
+ <div id="access-level">
+ <% if (result.toLowerCase() == 'yes') { %>
+ This user has <span class="<%= accessLevel.toLowerCase() %>"><%= accessLevel %></span> access to this application ( appId: <%= appId %> )
+ <% } else { %>
+ This user has <span class="<%= result.toLowerCase() %>"><%= result %></span> access to this application ( appId: <%= appId %> )
+ <% } %>
+ </div>
+ </script>
+ </head>
+ <body>
+ <nav>
+ <?php if (!isset($_SESSION['userId'])): ?>
+ <a href="javascript:" onclick="openPopup(450, 500, this);">Sign in</a>
+ <?php else: ?>
+ <span>Welcome <?php echo @$_SESSION['attributes']['namePerson/first'] ?> <?php echo @$_SESSION['attributes']['namePerson/last'] ?> ( <?php echo $_SESSION['attributes']['contact/email'] ?> )</span>
+ <a href="?logout">Sign out</a>
+ <?php endif; ?>
+ </nav>
+ <?php if (isset($_SESSION['attributes'])): ?>
+ <div id="container">
+ <form action="<?php echo "$selfUrl?queryLicenseServer" ?>" onsubmit="return queryLicenseServer(this);">
+ <input type="hidden" id="user_id" name="user_id" value="<?php echo $_SESSION['userId'] ?>" />
+ <input type="submit" value="Check user's access" />
+ </form>
+ <div id="license-server-response"></div>
+ </div>
+ <?php endif; ?>
+ <script>
+ // Simple JavaScript Templating
+ // John Resig - http://ejohn.org/ - MIT Licensed
+ (function(){
+ var cache = {};
+
+ this.tmpl = function tmpl(str, data){
+ // Figure out if we're getting a template, or if we need to
+ // load the template - and be sure to cache the result.
+ var fn = !/\W/.test(str) ?
+ cache[str] = cache[str] ||
+ tmpl(document.getElementById(str).innerHTML) :
+
+ // Generate a reusable function that will serve as a template
+ // generator (and which will be cached).
+ new Function("obj",
+ "var p=[],print=function(){p.push.apply(p,arguments);};" +
+
+ // Introduce the data as local variables using with(){}
+ "with(obj){p.push('" +
+
+ // Convert the template into pure JavaScript
+ str
+ .replace(/[\r\t\n]/g, " ")
+ .split("<%").join("\t")
+ .replace(/((^|%>)[^\t]*)'/g, "$1\r")
+ .replace(/\t=(.*?)%>/g, "',$1,'")
+ .split("\t").join("');")
+ .split("%>").join("p.push('")
+ .split("\r").join("\\'")
+ + "');}return p.join('');");
+
+ // Provide some basic currying to the user
+ return data ? fn( data ) : fn;
+ };
+ })();
+
+ function queryLicenseServer(form) {
+ var userId = form.user_id.value;
+
+ if (!userId) {
+ alert('No OpenID specified!');
+ return false;
+ }
+
+ var req = new XMLHttpRequest();
+ req.onreadystatechange = function(e) {
+ if (this.readyState == 4) {
+ var resp = JSON.parse(this.responseText);
+ var el = document.getElementById('license-server-response');
+ if (resp.error) {
+ el.innerHTML = ['<div class="error">Error ', resp.error.code,
+ ': ', resp.error.message, '</div>'].join('');
+ } else {
+ el.innerHTML = tmpl('ls_tmpl', resp);
+ }
+ }
+ };
+ var url =
+ [form.action, '&user_id=', encodeURIComponent(userId)].join('');
+ req.open('GET', url, true);
+ req.send(null);
+
+ return false;
+ }
+
+ function openPopup(w, h, link) {
+ var extensions = {
+ 'openid.ns.ext1': 'http://openid.net/srv/ax/1.0',
+ 'openid.ext1.mode': 'fetch_request',
+ 'openid.ext1.type.email': 'http://axschema.org/contact/email',
+ 'openid.ext1.type.first': 'http://axschema.org/namePerson/first',
+ 'openid.ext1.type.last': 'http://axschema.org/namePerson/last',
+ 'openid.ext1.required': 'email,first,last',
+ 'openid.ui.icon': 'true'
+ };
+
+ var googleOpener = popupManager.createPopupOpener({
+ opEndpoint: 'https://www.google.com/accounts/o8/ud',
+ returnToUrl: '<?php echo "$selfUrl?popup=true" ?>',
+ onCloseHandler: function() {
+ window.location = '<?php echo $selfUrl ?>';
+ },
+ shouldEncodeUrls: false,
+ extensions: extensions
+ });
+ link.parentNode.appendChild(
+ document.createTextNode('Authenticating...'));
+ link.parentNode.removeChild(link);
+ googleOpener.popup(w, h);
+ }
+ </script>
+ </body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/lib/lightopenid/openid.php b/chrome/common/extensions/docs/examples/apps/hello-php/lib/lightopenid/openid.php
new file mode 100644
index 0000000..2f5b0ff
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/lib/lightopenid/openid.php
@@ -0,0 +1,563 @@
+<?php
+/**
+ * This class provides a simple interface for OpenID (1.1 and 2.0) authentication.
+ * Supports Yadis discovery.
+ * The authentication process is stateless/dumb.
+ *
+ * Usage:
+ * Sign-on with OpenID is a two step process:
+ * Step one is authentication with the provider:
+ * <code>
+ * $openid = new LightOpenID;
+ * $openid->identity = 'ID supplied by user';
+ * header('Location: ' . $openid->authUrl());
+ * </code>
+ * The provider then sends various parameters via GET, one of them is openid_mode.
+ * Step two is verification:
+ * <code>
+ * if ($this->data['openid_mode']) {
+ * $openid = new LightOpenID;
+ * echo $openid->validate() ? 'Logged in.' : 'Failed';
+ * }
+ * </code>
+ *
+ * Optionally, you can set $returnUrl and $realm (or $trustRoot, which is an alias).
+ * The default values for those are:
+ * $openid->realm = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'];
+ * $openid->returnUrl = $openid->realm . $_SERVER['REQUEST_URI'];
+ * If you don't know their meaning, refer to any openid tutorial, or specification. Or just guess.
+ *
+ * AX and SREG extensions are supported.
+ * To use them, specify $openid->required and/or $openid->optional.
+ * These are arrays, with values being AX schema paths (the 'path' part of the URL).
+ * For example:
+ * $openid->required = array('namePerson/friendly', 'contact/email');
+ * $openid->optional = array('namePerson/first');
+ * If the server supports only SREG or OpenID 1.1, these are automaticaly
+ * mapped to SREG names, so that user doesn't have to know anything about the server.
+ *
+ * To get the values, use $openid->getAttributes().
+ *
+ *
+ * The library depends on curl, and requires PHP 5.
+ * @author Mewp
+ * @copyright Copyright (c) 2010, Mewp
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ */
+class LightOpenID
+{
+ public $returnUrl
+ , $required = array()
+ , $optional = array();
+ private $identity, $claimed_id;
+ protected $server, $version, $trustRoot, $aliases, $identifier_select = false
+ , $ax = false, $sreg = false, $data;
+ static protected $ax_to_sreg = array(
+ 'namePerson/friendly' => 'nickname',
+ 'contact/email' => 'email',
+ 'namePerson' => 'fullname',
+ 'birthDate' => 'dob',
+ 'person/gender' => 'gender',
+ 'contact/postalCode/home' => 'postcode',
+ 'contact/country/home' => 'country',
+ 'pref/language' => 'language',
+ 'pref/timezone' => 'timezone',
+ );
+
+ function __construct()
+ {
+ $this->trustRoot = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'];
+ $this->returnUrl = $this->trustRoot . $_SERVER['REQUEST_URI'];
+
+ if (!function_exists('curl_exec')) {
+ throw new ErrorException('Curl extension is required.');
+ }
+
+ $this->data = $_POST + $_GET; # OPs may send data as POST or GET.
+ }
+
+ function __set($name, $value)
+ {
+ switch ($name) {
+ case 'identity':
+ if (strlen($value = trim($value))) {
+ if (preg_match('#^xri:/*#i', $value, $m)) {
+ $value = substr($value, strlen($m[0]));
+ } elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) {
+ $value = "http://$value";
+ }
+ if (preg_match('#^https?://[^/]+$#i', $value, $m)) {
+ $value .= '/';
+ }
+ }
+ $this->$name = $this->claimed_id = $value;
+ break;
+ case 'trustRoot':
+ case 'realm':
+ $this->trustRoot = trim($value);
+ }
+ }
+
+ function __get($name)
+ {
+ switch ($name) {
+ case 'identity':
+ # We return claimed_id instead of identity,
+ # because the developer should see the claimed identifier,
+ # i.e. what he set as identity, not the op-local identifier (which is what we verify)
+ return $this->claimed_id;
+ case 'trustRoot':
+ case 'realm':
+ return $this->trustRoot;
+ }
+ }
+
+ protected function request($url, $method='GET', $params=array())
+ {
+ $params = http_build_query($params, '', '&');
+ $curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : ''));
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($curl, CURLOPT_HEADER, false);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ if ($method == 'POST') {
+ curl_setopt($curl, CURLOPT_POST, true);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
+ } elseif ($method == 'HEAD') {
+ curl_setopt($curl, CURLOPT_HEADER, true);
+ curl_setopt($curl, CURLOPT_NOBODY, true);
+ } else {
+ curl_setopt($curl, CURLOPT_HTTPGET, true);
+ }
+ $response = curl_exec($curl);
+
+ if (curl_errno($curl)) {
+ throw new ErrorException(curl_error($curl), curl_errno($curl));
+ }
+
+ return $response;
+ }
+
+ protected function build_url($url, $parts)
+ {
+ if (isset($url['query'], $parts['query'])) {
+ $parts['query'] = $url['query'] . '&' . $parts['query'];
+ }
+
+ $url = $parts + $url;
+ $url = $url['scheme'] . '://'
+ . (empty($url['username'])?''
+ :(empty($url['password'])? "{$url['username']}@"
+ :"{$url['username']}:{$url['password']}@"))
+ . $url['host']
+ . (empty($url['port'])?'':":{$url['port']}")
+ . (empty($url['path'])?'':$url['path'])
+ . (empty($url['query'])?'':"?{$url['query']}")
+ . (empty($url['fragment'])?'':":{$url['fragment']}");
+ return $url;
+ }
+
+ /**
+ * Helper function used to scan for <meta>/<link> tags and extract information
+ * from them
+ */
+ protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName)
+ {
+ preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1);
+ preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2);
+
+ $result = array_merge($matches1[1], $matches2[1]);
+ return empty($result)?false:$result[0];
+ }
+
+ /**
+ * Performs Yadis and HTML discovery. Normally not used.
+ * @param $url Identity URL.
+ * @return String OP Endpoint (i.e. OpenID provider address).
+ * @throws ErrorException
+ */
+ function discover($url)
+ {
+ if (!$url) throw new ErrorException('No identity supplied.');
+ # Use xri.net proxy to resolve i-name identities
+ if (!preg_match('#^https?:#', $url)) {
+ $url = "https://xri.net/$url";
+ }
+
+ # We save the original url in case of Yadis discovery failure.
+ # It can happen when we'll be lead to an XRDS document
+ # which does not have any OpenID2 services.
+ $originalUrl = $url;
+
+ # A flag to disable yadis discovery in case of failure in headers.
+ $yadis = true;
+
+ # We'll jump a maximum of 5 times, to avoid endless redirections.
+ for ($i = 0; $i < 5; $i ++) {
+ if ($yadis) {
+ $headers = explode("\n",$this->request($url, 'HEAD'));
+
+ $next = false;
+ foreach ($headers as $header) {
+ if (preg_match('#X-XRDS-Location\s*:\s*(.*)#', $header, $m)) {
+ $url = $this->build_url(parse_url($url), parse_url(trim($m[1])));
+ $next = true;
+ }
+
+ if (preg_match('#Content-Type\s*:\s*application/xrds\+xml#i', $header)) {
+ # Found an XRDS document, now let's find the server, and optionally delegate.
+ $content = $this->request($url, 'GET');
+
+ # OpenID 2
+ # We ignore it for MyOpenID, as it breaks sreg if using OpenID 2.0
+ $ns = preg_quote('http://specs.openid.net/auth/2.0/');
+ if (preg_match('#<Service.*?>(.*)<Type>\s*'.$ns.'(.*?)\s*</Type>(.*)</Service>#s', $content, $m)) {
+ $content = ' ' . $m[1] . $m[3]; # The space is added, so that strpos doesn't return 0.
+ if ($m[2] == 'server') $this->identifier_select = true;
+
+ preg_match('#<URI.*?>(.*)</URI>#', $content, $server);
+ preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate);
+ if (empty($server)) {
+ return false;
+ }
+ # Does the server advertise support for either AX or SREG?
+ $this->ax = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>');
+ $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>')
+ || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>');
+
+ $server = $server[1];
+ if (isset($delegate[2])) $this->identity = trim($delegate[2]);
+ $this->version = 2;
+
+ $this->server = $server;
+ return $server;
+ }
+
+ # OpenID 1.1
+ $ns = preg_quote('http://openid.net/signon/1.1');
+ if (preg_match('#<Service.*?>(.*)<Type>\s*'.$ns.'\s*</Type>(.*)</Service>#s', $content, $m)) {
+ $content = ' ' . $m[1] . $m[2];
+
+ preg_match('#<URI.*?>(.*)</URI>#', $content, $server);
+ preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate);
+ if (empty($server)) {
+ return false;
+ }
+ # AX can be used only with OpenID 2.0, so checking only SREG
+ $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>')
+ || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>');
+
+ $server = $server[1];
+ if (isset($delegate[1])) $this->identity = $delegate[1];
+ $this->version = 1;
+
+ $this->server = $server;
+ return $server;
+ }
+
+ $next = true;
+ $yadis = false;
+ $url = $originalUrl;
+ $content = null;
+ break;
+ }
+ }
+ if ($next) continue;
+
+ # There are no relevant information in headers, so we search the body.
+ $content = $this->request($url, 'GET');
+ if ($location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'value')) {
+ $url = $this->build_url(parse_url($url), parse_url($location));
+ continue;
+ }
+ }
+
+ if (!$content) $content = $this->request($url, 'GET');
+
+ # At this point, the YADIS Discovery has failed, so we'll switch
+ # to openid2 HTML discovery, then fallback to openid 1.1 discovery.
+ $server = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href');
+ $delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href');
+ $this->version = 2;
+
+ if (!$server) {
+ # The same with openid 1.1
+ $server = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href');
+ $delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href');
+ $this->version = 1;
+ }
+
+ if ($server) {
+ # We found an OpenID2 OP Endpoint
+ if ($delegate) {
+ # We have also found an OP-Local ID.
+ $this->identity = $delegate;
+ }
+ $this->server = $server;
+ return $server;
+ }
+
+ throw new ErrorException('No servers found!');
+ }
+ throw new ErrorException('Endless redirection!');
+ }
+
+ protected function sregParams()
+ {
+ $params = array();
+ # We always use SREG 1.1, even if the server is advertising only support for 1.0.
+ # That's because it's fully backwards compatibile with 1.0, and some providers
+ # advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com
+ $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1';
+ if ($this->required) {
+ $params['openid.sreg.required'] = array();
+ foreach ($this->required as $required) {
+ if (!isset(self::$ax_to_sreg[$required])) continue;
+ $params['openid.sreg.required'][] = self::$ax_to_sreg[$required];
+ }
+ $params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']);
+ }
+
+ if ($this->optional) {
+ $params['openid.sreg.optional'] = array();
+ foreach ($this->optional as $optional) {
+ if (!isset(self::$ax_to_sreg[$optional])) continue;
+ $params['openid.sreg.optional'][] = self::$ax_to_sreg[$optional];
+ }
+ $params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']);
+ }
+ return $params;
+ }
+ protected function axParams()
+ {
+ $params = array();
+ if ($this->required || $this->optional) {
+ $params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0';
+ $params['openid.ax.mode'] = 'fetch_request';
+ $this->aliases = array();
+ $counts = array();
+ $required = array();
+ $optional = array();
+ foreach (array('required','optional') as $type) {
+ foreach ($this->$type as $alias => $field) {
+ if (is_int($alias)) $alias = strtr($field, '/', '_');
+ $this->aliases[$alias] = 'http://axschema.org/' . $field;
+ if (empty($counts[$alias])) $counts[$alias] = 0;
+ $counts[$alias] += 1;
+ ${$type}[] = $alias;
+ }
+ }
+ foreach ($this->aliases as $alias => $ns) {
+ $params['openid.ax.type.' . $alias] = $ns;
+ }
+ foreach ($counts as $alias => $count) {
+ if ($count == 1) continue;
+ $params['openid.ax.count.' . $alias] = $count;
+ }
+
+ # Don't send empty ax.requied and ax.if_available.
+ # Google and possibly other providers refuse to support ax when one of these is empty.
+ if($required) {
+ $params['openid.ax.required'] = implode(',', $required);
+ }
+ if($optional) {
+ $params['openid.ax.if_available'] = implode(',', $optional);
+ }
+ }
+ return $params;
+ }
+
+ protected function authUrl_v1()
+ {
+ $returnUrl = $this->returnUrl;
+ # If we have an openid.delegate that is different from our claimed id,
+ # we need to somehow preserve the claimed id between requests.
+ # The simplest way is to just send it along with the return_to url.
+ if($this->identity != $this->claimed_id) {
+ $returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id;
+ }
+
+ $params = array(
+ 'openid.return_to' => $returnUrl,
+ 'openid.mode' => 'checkid_setup',
+ 'openid.identity' => $this->identity,
+ 'openid.trust_root' => $this->trustRoot,
+ ) + $this->sregParams();
+
+ return $this->build_url(parse_url($this->server)
+ , array('query' => http_build_query($params, '', '&')));
+ }
+
+ protected function authUrl_v2($identifier_select)
+ {
+ $params = array(
+ 'openid.ns' => 'http://specs.openid.net/auth/2.0',
+ 'openid.mode' => 'checkid_setup',
+ 'openid.return_to' => $this->returnUrl,
+ 'openid.realm' => $this->trustRoot,
+ );
+ if ($this->ax) {
+ $params += $this->axParams();
+ }
+ if ($this->sreg) {
+ $params += $this->sregParams();
+ }
+ if (!$this->ax && !$this->sreg) {
+ # If OP doesn't advertise either SREG, nor AX, let's send them both
+ # in worst case we don't get anything in return.
+ $params += $this->axParams() + $this->sregParams();
+ }
+
+ if ($identifier_select) {
+ $params['openid.identity'] = $params['openid.claimed_id']
+ = 'http://specs.openid.net/auth/2.0/identifier_select';
+ } else {
+ $params['openid.identity'] = $this->identity;
+ $params['openid.claimed_id'] = $this->claimed_id;
+ }
+
+ return $this->build_url(parse_url($this->server)
+ , array('query' => http_build_query($params, '', '&')));
+ }
+
+ /**
+ * Returns authentication url. Usually, you want to redirect your user to it.
+ * @return String The authentication url.
+ * @param String $select_identifier Whether to request OP to select identity for an user in OpenID 2. Does not affect OpenID 1.
+ * @throws ErrorException
+ */
+ function authUrl($identifier_select = null)
+ {
+ if (!$this->server) $this->discover($this->identity);
+
+ if ($this->version == 2) {
+ if ($identifier_select === null) {
+ return $this->authUrl_v2($this->identifier_select);
+ }
+ return $this->authUrl_v2($identifier_select);
+ }
+ return $this->authUrl_v1();
+ }
+
+ /**
+ * Performs OpenID verification with the OP.
+ * @return Bool Whether the verification was successful.
+ * @throws ErrorException
+ */
+ function validate()
+ {
+ $this->claimed_id = isset($this->data['openid_claimed_id'])?$this->data['openid_claimed_id']:$this->data['openid_identity'];
+ $params = array(
+ 'openid.assoc_handle' => $this->data['openid_assoc_handle'],
+ 'openid.signed' => $this->data['openid_signed'],
+ 'openid.sig' => $this->data['openid_sig'],
+ );
+
+ if (isset($this->data['openid_op_endpoint'])) {
+ # We're dealing with an OpenID 2.0 server, so let's set an ns
+ # Even though we should know location of the endpoint,
+ # we still need to verify it by discovery, so $server is not set here
+ $params['openid.ns'] = 'http://specs.openid.net/auth/2.0';
+ }
+ $server = $this->discover($this->data['openid_identity']);
+
+ foreach (explode(',', $this->data['openid_signed']) as $item) {
+ # Checking whether magic_quotes_gpc is turned on, because
+ # the function may fail if it is. For example, when fetching
+ # AX namePerson, it might containg an apostrophe, which will be escaped.
+ # In such case, validation would fail, since we'd send different data than OP
+ # wants to verify. stripslashes() should solve that problem, but we can't
+ # use it when magic_quotes is off.
+ $value = $this->data['openid_' . str_replace('.','_',$item)];
+ $params['openid.' . $item] = get_magic_quotes_gpc() ? stripslashes($value) : $value;
+ }
+
+ $params['openid.mode'] = 'check_authentication';
+
+ $response = $this->request($server, 'POST', $params);
+
+ return preg_match('/is_valid\s*:\s*true/i', $response);
+ }
+ protected function getAxAttributes()
+ {
+ $alias = null;
+ if (isset($this->data['openid_ns_ax'])
+ && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0'
+ ) { # It's the most likely case, so we'll check it before
+ $alias = 'ax';
+ } else {
+ # 'ax' prefix is either undefined, or points to another extension,
+ # so we search for another prefix
+ foreach ($this->data as $key => $val) {
+ if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_'
+ && $val == 'http://openid.net/srv/ax/1.0'
+ ) {
+ $alias = substr($key, strlen('openid_ns_'));
+ break;
+ }
+ }
+ }
+ if (!$alias) {
+ # An alias for AX schema has not been found,
+ # so there is no AX data in the OP's response
+ return array();
+ }
+
+ foreach ($this->data as $key => $value) {
+ $keyMatch = 'openid_' . $alias . '_value_';
+ if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
+ continue;
+ }
+ $key = substr($key, strlen($keyMatch));
+ if (!isset($this->data['openid_' . $alias . '_type_' . $key])) {
+ # OP is breaking the spec by returning a field without
+ # associated ns. This shouldn't happen, but it's better
+ # to check, than cause an E_NOTICE.
+ continue;
+ }
+ $key = substr($this->data['openid_' . $alias . '_type_' . $key],
+ strlen('http://axschema.org/'));
+ $attributes[$key] = $value;
+ }
+ # Found the AX attributes, so no need to scan for SREG.
+ return $attributes;
+ }
+ protected function getSregAttributes()
+ {
+ $attributes = array();
+ $sreg_to_ax = array_flip(self::$ax_to_sreg);
+ foreach ($this->data as $key => $value) {
+ $keyMatch = 'openid_sreg_';
+ if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
+ continue;
+ }
+ $key = substr($key, strlen($keyMatch));
+ if (!isset($sreg_to_ax[$key])) {
+ # The field name isn't part of the SREG spec, so we ignore it.
+ continue;
+ }
+ $attributes[$sreg_to_ax[$key]] = $value;
+ }
+ return $attributes;
+ }
+ /**
+ * Gets AX/SREG attributes provided by OP. should be used only after successful validaton.
+ * Note that it does not guarantee that any of the required/optional parameters will be present,
+ * or that there will be no other attributes besides those specified.
+ * In other words. OP may provide whatever information it wants to.
+ * * SREG names will be mapped to AX names.
+ * * @return Array Array of attributes with keys being the AX schema names, e.g. 'contact/email'
+ * @see http://www.axschema.org/types/
+ */
+ function getAttributes()
+ {
+ $attributes;
+ if (isset($this->data['openid_ns'])
+ && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0'
+ ) { # OpenID 2.0
+ # We search for both AX and SREG attributes, with AX taking precedence.
+ return $this->getAxAttributes() + $this->getSregAttributes();
+ }
+ return $this->getSregAttributes();
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/CHANGELOG.txt b/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/CHANGELOG.txt
new file mode 100644
index 0000000..b12ff1c
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/CHANGELOG.txt
@@ -0,0 +1,15 @@
+== 2008.08.04 ==
+* Added LICENSE.txt file with MIT license, copyright owner is perhaps
+ dubious however.
+== 2008.07.22 ==
+* Change to encoding to fix last change to encoding of spaces
+== 2008.07.15 ==
+* Another change to encoding per
+ http://groups.google.com/group/oauth/browse_thread/thread/d39931d39b4af4bd
+* A change to port handling to better deal with https and the like per
+ http://groups.google.com/group/oauth/browse_thread/thread/1b203a51d9590226
+* Fixed a small bug per
+ http://code.google.com/p/oauth/issues/detail?id=26
+* Added missing base_string debug info when using RSA-SHA1
+* Increased size of example endpoint input field and added note about
+ query strings
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/LICENSE.txt b/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/LICENSE.txt
new file mode 100644
index 0000000..89f0591
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/LICENSE.txt
@@ -0,0 +1,22 @@
+The MIT License
+
+Copyright (c) 2007 Andy Smith
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/OAuth.php b/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/OAuth.php
new file mode 100644
index 0000000..e9c4bdf
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/lib/oauth/OAuth.php
@@ -0,0 +1,879 @@
+<?php
+// vim: foldmethod=marker
+
+/* Generic exception class
+ */
+class OAuthException extends Exception {
+ // pass
+}
+
+class OAuthConsumer {
+ public $key;
+ public $secret;
+
+ function __construct($key, $secret, $callback_url=NULL) {
+ $this->key = $key;
+ $this->secret = $secret;
+ $this->callback_url = $callback_url;
+ }
+
+ function __toString() {
+ return "OAuthConsumer[key=$this->key,secret=$this->secret]";
+ }
+}
+
+class OAuthToken {
+ // access tokens and request tokens
+ public $key;
+ public $secret;
+
+ /**
+ * key = the token
+ * secret = the token secret
+ */
+ function __construct($key, $secret) {
+ $this->key = $key;
+ $this->secret = $secret;
+ }
+
+ /**
+ * generates the basic string serialization of a token that a server
+ * would respond to request_token and access_token calls with
+ */
+ function to_string() {
+ return "oauth_token=" .
+ OAuthUtil::urlencode_rfc3986($this->key) .
+ "&oauth_token_secret=" .
+ OAuthUtil::urlencode_rfc3986($this->secret);
+ }
+
+ function __toString() {
+ return $this->to_string();
+ }
+}
+
+/**
+ * A class for implementing a Signature Method
+ * See section 9 ("Signing Requests") in the spec
+ */
+abstract class OAuthSignatureMethod {
+ /**
+ * Needs to return the name of the Signature Method (ie HMAC-SHA1)
+ * @return string
+ */
+ abstract public function get_name();
+
+ /**
+ * Build up the signature
+ * NOTE: The output of this function MUST NOT be urlencoded.
+ * the encoding is handled in OAuthRequest when the final
+ * request is serialized
+ * @param OAuthRequest $request
+ * @param OAuthConsumer $consumer
+ * @param OAuthToken $token
+ * @return string
+ */
+ abstract public function build_signature($request, $consumer, $token);
+
+ /**
+ * Verifies that a given signature is correct
+ * @param OAuthRequest $request
+ * @param OAuthConsumer $consumer
+ * @param OAuthToken $token
+ * @param string $signature
+ * @return bool
+ */
+ public function check_signature($request, $consumer, $token, $signature) {
+ $built = $this->build_signature($request, $consumer, $token);
+ return $built == $signature;
+ }
+}
+
+/**
+ * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
+ * where the Signature Base String is the text and the key is the concatenated values (each first
+ * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
+ * character (ASCII code 38) even if empty.
+ * - Chapter 9.2 ("HMAC-SHA1")
+ */
+class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
+ function get_name() {
+ return "HMAC-SHA1";
+ }
+
+ public function build_signature($request, $consumer, $token) {
+ $base_string = $request->get_signature_base_string();
+ $request->base_string = $base_string;
+
+ $key_parts = array(
+ $consumer->secret,
+ ($token) ? $token->secret : ""
+ );
+
+ $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
+ $key = implode('&', $key_parts);
+
+ return base64_encode(hash_hmac('sha1', $base_string, $key, true));
+ }
+}
+
+/**
+ * The PLAINTEXT method does not provide any security protection and SHOULD only be used
+ * over a secure channel such as HTTPS. It does not use the Signature Base String.
+ * - Chapter 9.4 ("PLAINTEXT")
+ */
+class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
+ public function get_name() {
+ return "PLAINTEXT";
+ }
+
+ /**
+ * oauth_signature is set to the concatenated encoded values of the Consumer Secret and
+ * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
+ * empty. The result MUST be encoded again.
+ * - Chapter 9.4.1 ("Generating Signatures")
+ *
+ * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
+ * OAuthRequest handles this!
+ */
+ public function build_signature($request, $consumer, $token) {
+ $key_parts = array(
+ $consumer->secret,
+ ($token) ? $token->secret : ""
+ );
+
+ $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
+ $key = implode('&', $key_parts);
+ $request->base_string = $key;
+
+ return $key;
+ }
+}
+
+/**
+ * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
+ * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
+ * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
+ * verified way to the Service Provider, in a manner which is beyond the scope of this
+ * specification.
+ * - Chapter 9.3 ("RSA-SHA1")
+ */
+abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
+ public function get_name() {
+ return "RSA-SHA1";
+ }
+
+ // Up to the SP to implement this lookup of keys. Possible ideas are:
+ // (1) do a lookup in a table of trusted certs keyed off of consumer
+ // (2) fetch via http using a url provided by the requester
+ // (3) some sort of specific discovery code based on request
+ //
+ // Either way should return a string representation of the certificate
+ protected abstract function fetch_public_cert(&$request);
+
+ // Up to the SP to implement this lookup of keys. Possible ideas are:
+ // (1) do a lookup in a table of trusted certs keyed off of consumer
+ //
+ // Either way should return a string representation of the certificate
+ protected abstract function fetch_private_cert(&$request);
+
+ public function build_signature($request, $consumer, $token) {
+ $base_string = $request->get_signature_base_string();
+ $request->base_string = $base_string;
+
+ // Fetch the private key cert based on the request
+ $cert = $this->fetch_private_cert($request);
+
+ // Pull the private key ID from the certificate
+ $privatekeyid = openssl_get_privatekey($cert);
+
+ // Sign using the key
+ $ok = openssl_sign($base_string, $signature, $privatekeyid);
+
+ // Release the key resource
+ openssl_free_key($privatekeyid);
+
+ return base64_encode($signature);
+ }
+
+ public function check_signature($request, $consumer, $token, $signature) {
+ $decoded_sig = base64_decode($signature);
+
+ $base_string = $request->get_signature_base_string();
+
+ // Fetch the public key cert based on the request
+ $cert = $this->fetch_public_cert($request);
+
+ // Pull the public key ID from the certificate
+ $publickeyid = openssl_get_publickey($cert);
+
+ // Check the computed signature against the one passed in the query
+ $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
+
+ // Release the key resource
+ openssl_free_key($publickeyid);
+
+ return $ok == 1;
+ }
+}
+
+class OAuthRequest {
+ protected $parameters;
+ protected $http_method;
+ protected $http_url;
+ // for debug purposes
+ public $base_string;
+ public static $version = '1.0';
+ public static $POST_INPUT = 'php://input';
+
+ function __construct($http_method, $http_url, $parameters=NULL) {
+ $parameters = ($parameters) ? $parameters : array();
+ $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
+ $this->parameters = $parameters;
+ $this->http_method = $http_method;
+ $this->http_url = $http_url;
+ }
+
+
+ /**
+ * attempt to build up a request from what was passed to the server
+ */
+ public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
+ $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
+ ? 'http'
+ : 'https';
+ $http_url = ($http_url) ? $http_url : $scheme .
+ '://' . $_SERVER['HTTP_HOST'] .
+ ':' .
+ $_SERVER['SERVER_PORT'] .
+ $_SERVER['REQUEST_URI'];
+ $http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD'];
+
+ // We weren't handed any parameters, so let's find the ones relevant to
+ // this request.
+ // If you run XML-RPC or similar you should use this to provide your own
+ // parsed parameter-list
+ if (!$parameters) {
+ // Find request headers
+ $request_headers = OAuthUtil::get_headers();
+
+ // Parse the query-string to find GET parameters
+ $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
+
+ // It's a POST request of the proper content-type, so parse POST
+ // parameters and add those overriding any duplicates from GET
+ if ($http_method == "POST"
+ && isset($request_headers['Content-Type'])
+ && strstr($request_headers['Content-Type'],
+ 'application/x-www-form-urlencoded')
+ ) {
+ $post_data = OAuthUtil::parse_parameters(
+ file_get_contents(self::$POST_INPUT)
+ );
+ $parameters = array_merge($parameters, $post_data);
+ }
+
+ // We have a Authorization-header with OAuth data. Parse the header
+ // and add those overriding any duplicates from GET or POST
+ if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') {
+ $header_parameters = OAuthUtil::split_header(
+ $request_headers['Authorization']
+ );
+ $parameters = array_merge($parameters, $header_parameters);
+ }
+
+ }
+
+ return new OAuthRequest($http_method, $http_url, $parameters);
+ }
+
+ /**
+ * pretty much a helper function to set up the request
+ */
+ public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
+ $parameters = ($parameters) ? $parameters : array();
+ $defaults = array("oauth_version" => OAuthRequest::$version,
+ "oauth_nonce" => OAuthRequest::generate_nonce(),
+ "oauth_timestamp" => OAuthRequest::generate_timestamp(),
+ "oauth_consumer_key" => $consumer->key);
+ if ($token)
+ $defaults['oauth_token'] = $token->key;
+
+ $parameters = array_merge($defaults, $parameters);
+
+ return new OAuthRequest($http_method, $http_url, $parameters);
+ }
+
+ public function set_parameter($name, $value, $allow_duplicates = true) {
+ if ($allow_duplicates && isset($this->parameters[$name])) {
+ // We have already added parameter(s) with this name, so add to the list
+ if (is_scalar($this->parameters[$name])) {
+ // This is the first duplicate, so transform scalar (string)
+ // into an array so we can add the duplicates
+ $this->parameters[$name] = array($this->parameters[$name]);
+ }
+
+ $this->parameters[$name][] = $value;
+ } else {
+ $this->parameters[$name] = $value;
+ }
+ }
+
+ public function get_parameter($name) {
+ return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
+ }
+
+ public function get_parameters() {
+ return $this->parameters;
+ }
+
+ public function unset_parameter($name) {
+ unset($this->parameters[$name]);
+ }
+
+ /**
+ * The request parameters, sorted and concatenated into a normalized string.
+ * @return string
+ */
+ public function get_signable_parameters() {
+ // Grab all parameters
+ $params = $this->parameters;
+
+ // Remove oauth_signature if present
+ // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
+ if (isset($params['oauth_signature'])) {
+ unset($params['oauth_signature']);
+ }
+
+ return OAuthUtil::build_http_query($params);
+ }
+
+ /**
+ * Returns the base string of this request
+ *
+ * The base string defined as the method, the url
+ * and the parameters (normalized), each urlencoded
+ * and the concated with &.
+ */
+ public function get_signature_base_string() {
+ $parts = array(
+ $this->get_normalized_http_method(),
+ $this->get_normalized_http_url(),
+ $this->get_signable_parameters()
+ );
+
+ $parts = OAuthUtil::urlencode_rfc3986($parts);
+
+ return implode('&', $parts);
+ }
+
+ /**
+ * just uppercases the http method
+ */
+ public function get_normalized_http_method() {
+ return strtoupper($this->http_method);
+ }
+
+ /**
+ * parses the url and rebuilds it to be
+ * scheme://host/path
+ */
+ public function get_normalized_http_url() {
+ $parts = parse_url($this->http_url);
+
+ $scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http';
+ $port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80');
+ $host = (isset($parts['host'])) ? $parts['host'] : '';
+ $path = (isset($parts['path'])) ? $parts['path'] : '';
+
+ if (($scheme == 'https' && $port != '443')
+ || ($scheme == 'http' && $port != '80')) {
+ $host = "$host:$port";
+ }
+ return "$scheme://$host$path";
+ }
+
+ /**
+ * builds a url usable for a GET request
+ */
+ public function to_url() {
+ $post_data = $this->to_postdata();
+ $out = $this->get_normalized_http_url();
+ if ($post_data) {
+ $out .= '?'.$post_data;
+ }
+ return $out;
+ }
+
+ /**
+ * builds the data one would send in a POST request
+ */
+ public function to_postdata() {
+ return OAuthUtil::build_http_query($this->parameters);
+ }
+
+ /**
+ * builds the Authorization: header
+ */
+ public function to_header($realm=null) {
+ $first = true;
+ if($realm) {
+ $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
+ $first = false;
+ } else
+ $out = 'Authorization: OAuth';
+
+ $total = array();
+ foreach ($this->parameters as $k => $v) {
+ if (substr($k, 0, 5) != "oauth") continue;
+ if (is_array($v)) {
+ throw new OAuthException('Arrays not supported in headers');
+ }
+ $out .= ($first) ? ' ' : ',';
+ $out .= OAuthUtil::urlencode_rfc3986($k) .
+ '="' .
+ OAuthUtil::urlencode_rfc3986($v) .
+ '"';
+ $first = false;
+ }
+ return $out;
+ }
+
+ public function __toString() {
+ return $this->to_url();
+ }
+
+
+ public function sign_request($signature_method, $consumer, $token) {
+ $this->set_parameter(
+ "oauth_signature_method",
+ $signature_method->get_name(),
+ false
+ );
+ $signature = $this->build_signature($signature_method, $consumer, $token);
+ $this->set_parameter("oauth_signature", $signature, false);
+ }
+
+ public function build_signature($signature_method, $consumer, $token) {
+ $signature = $signature_method->build_signature($this, $consumer, $token);
+ return $signature;
+ }
+
+ /**
+ * util function: current timestamp
+ */
+ private static function generate_timestamp() {
+ return time();
+ }
+
+ /**
+ * util function: current nonce
+ */
+ private static function generate_nonce() {
+ $mt = microtime();
+ $rand = mt_rand();
+
+ return md5($mt . $rand); // md5s look nicer than numbers
+ }
+}
+
+class OAuthServer {
+ protected $timestamp_threshold = 300; // in seconds, five minutes
+ protected $version = '1.0'; // hi blaine
+ protected $signature_methods = array();
+
+ protected $data_store;
+
+ function __construct($data_store) {
+ $this->data_store = $data_store;
+ }
+
+ public function add_signature_method($signature_method) {
+ $this->signature_methods[$signature_method->get_name()] =
+ $signature_method;
+ }
+
+ // high level functions
+
+ /**
+ * process a request_token request
+ * returns the request token on success
+ */
+ public function fetch_request_token(&$request) {
+ $this->get_version($request);
+
+ $consumer = $this->get_consumer($request);
+
+ // no token required for the initial token request
+ $token = NULL;
+
+ $this->check_signature($request, $consumer, $token);
+
+ // Rev A change
+ $callback = $request->get_parameter('oauth_callback');
+ $new_token = $this->data_store->new_request_token($consumer, $callback);
+
+ return $new_token;
+ }
+
+ /**
+ * process an access_token request
+ * returns the access token on success
+ */
+ public function fetch_access_token(&$request) {
+ $this->get_version($request);
+
+ $consumer = $this->get_consumer($request);
+
+ // requires authorized request token
+ $token = $this->get_token($request, $consumer, "request");
+
+ $this->check_signature($request, $consumer, $token);
+
+ // Rev A change
+ $verifier = $request->get_parameter('oauth_verifier');
+ $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
+
+ return $new_token;
+ }
+
+ /**
+ * verify an api call, checks all the parameters
+ */
+ public function verify_request(&$request) {
+ $this->get_version($request);
+ $consumer = $this->get_consumer($request);
+ $token = $this->get_token($request, $consumer, "access");
+ $this->check_signature($request, $consumer, $token);
+ return array($consumer, $token);
+ }
+
+ // Internals from here
+ /**
+ * version 1
+ */
+ private function get_version(&$request) {
+ $version = $request->get_parameter("oauth_version");
+ if (!$version) {
+ // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
+ // Chapter 7.0 ("Accessing Protected Ressources")
+ $version = '1.0';
+ }
+ if ($version !== $this->version) {
+ throw new OAuthException("OAuth version '$version' not supported");
+ }
+ return $version;
+ }
+
+ /**
+ * figure out the signature with some defaults
+ */
+ private function get_signature_method($request) {
+ $signature_method = $request instanceof OAuthRequest
+ ? $request->get_parameter("oauth_signature_method")
+ : NULL;
+
+ if (!$signature_method) {
+ // According to chapter 7 ("Accessing Protected Ressources") the signature-method
+ // parameter is required, and we can't just fallback to PLAINTEXT
+ throw new OAuthException('No signature method parameter. This parameter is required');
+ }
+
+ if (!in_array($signature_method,
+ array_keys($this->signature_methods))) {
+ throw new OAuthException(
+ "Signature method '$signature_method' not supported " .
+ "try one of the following: " .
+ implode(", ", array_keys($this->signature_methods))
+ );
+ }
+ return $this->signature_methods[$signature_method];
+ }
+
+ /**
+ * try to find the consumer for the provided request's consumer key
+ */
+ private function get_consumer($request) {
+ $consumer_key = $request instanceof OAuthRequest
+ ? $request->get_parameter("oauth_consumer_key")
+ : NULL;
+
+ if (!$consumer_key) {
+ throw new OAuthException("Invalid consumer key");
+ }
+
+ $consumer = $this->data_store->lookup_consumer($consumer_key);
+ if (!$consumer) {
+ throw new OAuthException("Invalid consumer");
+ }
+
+ return $consumer;
+ }
+
+ /**
+ * try to find the token for the provided request's token key
+ */
+ private function get_token($request, $consumer, $token_type="access") {
+ $token_field = $request instanceof OAuthRequest
+ ? $request->get_parameter('oauth_token')
+ : NULL;
+
+ $token = $this->data_store->lookup_token(
+ $consumer, $token_type, $token_field
+ );
+ if (!$token) {
+ throw new OAuthException("Invalid $token_type token: $token_field");
+ }
+ return $token;
+ }
+
+ /**
+ * all-in-one function to check the signature on a request
+ * should guess the signature method appropriately
+ */
+ private function check_signature($request, $consumer, $token) {
+ // this should probably be in a different method
+ $timestamp = $request instanceof OAuthRequest
+ ? $request->get_parameter('oauth_timestamp')
+ : NULL;
+ $nonce = $request instanceof OAuthRequest
+ ? $request->get_parameter('oauth_nonce')
+ : NULL;
+
+ $this->check_timestamp($timestamp);
+ $this->check_nonce($consumer, $token, $nonce, $timestamp);
+
+ $signature_method = $this->get_signature_method($request);
+
+ $signature = $request->get_parameter('oauth_signature');
+ $valid_sig = $signature_method->check_signature(
+ $request,
+ $consumer,
+ $token,
+ $signature
+ );
+
+ if (!$valid_sig) {
+ throw new OAuthException("Invalid signature");
+ }
+ }
+
+ /**
+ * check that the timestamp is new enough
+ */
+ private function check_timestamp($timestamp) {
+ if( ! $timestamp )
+ throw new OAuthException(
+ 'Missing timestamp parameter. The parameter is required'
+ );
+
+ // verify that timestamp is recentish
+ $now = time();
+ if (abs($now - $timestamp) > $this->timestamp_threshold) {
+ throw new OAuthException(
+ "Expired timestamp, yours $timestamp, ours $now"
+ );
+ }
+ }
+
+ /**
+ * check that the nonce is not repeated
+ */
+ private function check_nonce($consumer, $token, $nonce, $timestamp) {
+ if( ! $nonce )
+ throw new OAuthException(
+ 'Missing nonce parameter. The parameter is required'
+ );
+
+ // verify that the nonce is uniqueish
+ $found = $this->data_store->lookup_nonce(
+ $consumer,
+ $token,
+ $nonce,
+ $timestamp
+ );
+ if ($found) {
+ throw new OAuthException("Nonce already used: $nonce");
+ }
+ }
+
+}
+
+class OAuthDataStore {
+ function lookup_consumer($consumer_key) {
+ // implement me
+ }
+
+ function lookup_token($consumer, $token_type, $token) {
+ // implement me
+ }
+
+ function lookup_nonce($consumer, $token, $nonce, $timestamp) {
+ // implement me
+ }
+
+ function new_request_token($consumer, $callback = null) {
+ // return a new token attached to this consumer
+ }
+
+ function new_access_token($token, $consumer, $verifier = null) {
+ // return a new access token attached to this consumer
+ // for the user associated with this token if the request token
+ // is authorized
+ // should also invalidate the request token
+ }
+
+}
+
+class OAuthUtil {
+ public static function urlencode_rfc3986($input) {
+ if (is_array($input)) {
+ return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
+ } else if (is_scalar($input)) {
+ return str_replace(
+ '+',
+ ' ',
+ str_replace('%7E', '~', rawurlencode($input))
+ );
+ } else {
+ return '';
+ }
+}
+
+
+ // This decode function isn't taking into consideration the above
+ // modifications to the encoding process. However, this method doesn't
+ // seem to be used anywhere so leaving it as is.
+ public static function urldecode_rfc3986($string) {
+ return urldecode($string);
+ }
+
+ // Utility function for turning the Authorization: header into
+ // parameters, has to do some unescaping
+ // Can filter out any non-oauth parameters if needed (default behaviour)
+ // May 28th, 2010 - method updated to tjerk.meesters for a speed improvement.
+ // see http://code.google.com/p/oauth/issues/detail?id=163
+ public static function split_header($header, $only_allow_oauth_parameters = true) {
+ $params = array();
+ if (preg_match_all('/('.($only_allow_oauth_parameters ? 'oauth_' : '').'[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches)) {
+ foreach ($matches[1] as $i => $h) {
+ $params[$h] = OAuthUtil::urldecode_rfc3986(empty($matches[3][$i]) ? $matches[4][$i] : $matches[3][$i]);
+ }
+ if (isset($params['realm'])) {
+ unset($params['realm']);
+ }
+ }
+ return $params;
+ }
+
+ // helper to try to sort out headers for people who aren't running apache
+ public static function get_headers() {
+ if (function_exists('apache_request_headers')) {
+ // we need this to get the actual Authorization: header
+ // because apache tends to tell us it doesn't exist
+ $headers = apache_request_headers();
+
+ // sanitize the output of apache_request_headers because
+ // we always want the keys to be Cased-Like-This and arh()
+ // returns the headers in the same case as they are in the
+ // request
+ $out = array();
+ foreach ($headers AS $key => $value) {
+ $key = str_replace(
+ " ",
+ "-",
+ ucwords(strtolower(str_replace("-", " ", $key)))
+ );
+ $out[$key] = $value;
+ }
+ } else {
+ // otherwise we don't have apache and are just going to have to hope
+ // that $_SERVER actually contains what we need
+ $out = array();
+ if( isset($_SERVER['CONTENT_TYPE']) )
+ $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
+ if( isset($_ENV['CONTENT_TYPE']) )
+ $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
+
+ foreach ($_SERVER as $key => $value) {
+ if (substr($key, 0, 5) == "HTTP_") {
+ // this is chaos, basically it is just there to capitalize the first
+ // letter of every word that is not an initial HTTP and strip HTTP
+ // code from przemek
+ $key = str_replace(
+ " ",
+ "-",
+ ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
+ );
+ $out[$key] = $value;
+ }
+ }
+ }
+ return $out;
+ }
+
+ // This function takes a input like a=b&a=c&d=e and returns the parsed
+ // parameters like this
+ // array('a' => array('b','c'), 'd' => 'e')
+ public static function parse_parameters( $input ) {
+ if (!isset($input) || !$input) return array();
+
+ $pairs = explode('&', $input);
+
+ $parsed_parameters = array();
+ foreach ($pairs as $pair) {
+ $split = explode('=', $pair, 2);
+ $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
+ $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
+
+ if (isset($parsed_parameters[$parameter])) {
+ // We have already recieved parameter(s) with this name, so add to the list
+ // of parameters with this name
+
+ if (is_scalar($parsed_parameters[$parameter])) {
+ // This is the first duplicate, so transform scalar (string) into an array
+ // so we can add the duplicates
+ $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
+ }
+
+ $parsed_parameters[$parameter][] = $value;
+ } else {
+ $parsed_parameters[$parameter] = $value;
+ }
+ }
+ return $parsed_parameters;
+ }
+
+ public static function build_http_query($params) {
+ if (!$params) return '';
+
+ // Urlencode both keys and values
+ $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
+ $values = OAuthUtil::urlencode_rfc3986(array_values($params));
+ $params = array_combine($keys, $values);
+
+ // Parameters are sorted by name, using lexicographical byte value ordering.
+ // Ref: Spec: 9.1.1 (1)
+ uksort($params, 'strcmp');
+
+ $pairs = array();
+ foreach ($params as $parameter => $value) {
+ if (is_array($value)) {
+ // If two or more parameters share the same name, they are sorted by their value
+ // Ref: Spec: 9.1.1 (1)
+ // June 12th, 2010 - changed to sort because of issue 164 by hidetaka
+ sort($value, SORT_STRING);
+ foreach ($value as $duplicate_value) {
+ $pairs[] = $parameter . '=' . $duplicate_value;
+ }
+ } else {
+ $pairs[] = $parameter . '=' . $value;
+ }
+ }
+ // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
+ // Each name-value pair is separated by an '&' character (ASCII code 38)
+ return implode('&', $pairs);
+ }
+}
+
+?>
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/main.css b/chrome/common/extensions/docs/examples/apps/hello-php/main.css
new file mode 100644
index 0000000..26f8eb4
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/main.css
@@ -0,0 +1,90 @@
+body {
+ font-family: Arial, Verdana, san-serif;
+ font-size: 11pt;
+ color: #666;
+ margin: 0;
+}
+
+nav {
+ display: block; /* for older browsers */
+ text-align: right;
+ margin-bottom: 10px;
+ padding: 10px;
+ border-bottom: 1px solid #C6D2EB;
+ background: -moz-linear-gradient(top, #fff, #EEF1F9 60%, #EEF1F9);
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#EEF1F9), color-stop(.6, #EEF1F9));
+ text-shadow: 1px 1px 1px #fff;
+}
+
+nav span {
+ float: left;
+ font-weight: bold;
+}
+
+a {
+ color: #2F58A4;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+form {
+ margin: 0;
+}
+
+input[type='text'] {
+ padding: 3px;
+}
+
+li {
+ list-style: none;
+}
+
+.error {
+ margin: 10px 0 10px;
+ padding: 10px;
+ text-align: center;
+ border: 1px solid red;
+ color: red;
+ font-weight: bold;
+ background-color: #ffffcc;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ text-shadow: 2px 2px 2px #ccc;
+}
+
+#container {
+ margin-top: 10px;
+ padding: 10px;
+}
+
+#access-level {
+ text-align: center;
+ padding: 15px;
+ border: 1px dotted #C6D2EB;
+ font-size: 12pt;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+ width: 550px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#license-server-response span {
+ font-weight: bold;
+}
+
+#license-server-response span.full {
+ color: green;
+}
+
+#license-server-response span.free_trial {
+ color: orange;
+}
+
+#license-server-response span.no {
+ color: red;
+}
+
diff --git a/chrome/common/extensions/docs/examples/apps/hello-php/popuplib.js b/chrome/common/extensions/docs/examples/apps/hello-php/popuplib.js
new file mode 100644
index 0000000..4b0fd40
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/apps/hello-php/popuplib.js
@@ -0,0 +1,279 @@
+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+// PopupManager is a library to facilitate integration with OpenID
+// identity providers (OP)s that support a pop-up authentication interface.
+// To create a popup window, you first construct a popupOpener customized
+// for your site and a particular identity provider, E.g.:
+//
+// var googleOpener = popupManager.createOpener(openidParams);
+//
+// where 'openidParams' are customized for Google in this instance.
+// (typically you just change the openidpoint, the version number
+// (the openid.ns parameter) and the extensions based on what
+// the OP supports.
+// OpenID libraries can often discover these properties
+// automatically from the location of an XRD document.
+//
+// Then, you can either directly call
+// googleOpener.popup(width, height), where 'width' and 'height' are your choices
+// for popup size, or you can display a button 'Sign in with Google' and set the
+//..'onclick' handler of the button to googleOpener.popup()
+
+var popupManager = {};
+
+// Library constants
+
+popupManager.constants = {
+ 'darkCover' : 'popupManager_darkCover_div',
+ 'darkCoverStyle' : ['position:absolute;',
+ 'top:0px;',
+ 'left:0px;',
+ 'padding-right:0px;',
+ 'padding-bottom:0px;',
+ 'background-color:#000000;',
+ 'opacity:0.5;', //standard-compliant browsers
+ '-moz-opacity:0.5;', // old Mozilla
+ 'filter:alpha(opacity=0.5);', // IE
+ 'z-index:10000;',
+ 'width:100%;',
+ 'height:100%;'
+ ].join(''),
+ 'openidSpec' : {
+ 'identifier_select' : 'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select',
+ 'namespace2' : 'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0'
+ } };
+
+// Computes the size of the window contents. Returns a pair of
+// coordinates [width, height] which can be [0, 0] if it was not possible
+// to compute the values.
+popupManager.getWindowInnerSize = function() {
+ var width = 0;
+ var height = 0;
+ var elem = null;
+ if ('innerWidth' in window) {
+ // For non-IE
+ width = window.innerWidth;
+ height = window.innerHeight;
+ } else {
+ // For IE,
+ if (('BackCompat' === window.document.compatMode)
+ && ('body' in window.document)) {
+ elem = window.document.body;
+ } else if ('documentElement' in window.document) {
+ elem = window.document.documentElement;
+ }
+ if (elem !== null) {
+ width = elem.offsetWidth;
+ height = elem.offsetHeight;
+ }
+ }
+ return [width, height];
+};
+
+// Computes the coordinates of the parent window.
+// Gets the coordinates of the parent frame
+popupManager.getParentCoords = function() {
+ var width = 0;
+ var height = 0;
+ if ('screenLeft' in window) {
+ // IE-compatible variants
+ width = window.screenLeft;
+ height = window.screenTop;
+ } else if ('screenX' in window) {
+ // Firefox-compatible
+ width = window.screenX;
+ height = window.screenY;
+ }
+ return [width, height];
+};
+
+// Computes the coordinates of the new window, so as to center it
+// over the parent frame
+popupManager.getCenteredCoords = function(width, height) {
+ var parentSize = this.getWindowInnerSize();
+ var parentPos = this.getParentCoords();
+ var xPos = parentPos[0] +
+ Math.max(0, Math.floor((parentSize[0] - width) / 2));
+ var yPos = parentPos[1] +
+ Math.max(0, Math.floor((parentSize[1] - height) / 2));
+ return [xPos, yPos];
+};
+
+// A utility class, implements an onOpenHandler that darkens the screen
+// by overlaying it with a semi-transparent black layer. To use, ensure that
+// no screen element has a z-index at or above 10000.
+// This layer will be suppressed automatically after the screen closes.
+//
+// Note: If you want to perform other operations before opening the popup, but
+// also would like the screen to darken, you can define a custom handler
+// as such:
+// var myOnOpenHandler = function(inputs) {
+// .. do something
+// popupManager.darkenScreen();
+// .. something else
+// };
+// Then you pass myOnOpenHandler as input to the opener, as in:
+// var openidParams = {};
+// openidParams.onOpenHandler = myOnOpenHandler;
+// ... other customizations
+// var myOpener = popupManager.createOpener(openidParams);
+popupManager.darkenScreen = function() {
+ var darkCover = window.document.getElementById(window.popupManager.constants['darkCover']);
+ if (!darkCover) {
+ darkCover = window.document.createElement('div');
+ darkCover['id'] = window.popupManager.constants['darkCover'];
+ darkCover.setAttribute('style', window.popupManager.constants['darkCoverStyle']);
+ window.document.body.appendChild(darkCover);
+ }
+ darkCover.style.visibility = 'visible';
+};
+
+// Returns a an object that can open a popup window customized for an OP & RP.
+// to use you call var opener = popupManager.cretePopupOpener(openidParams);
+// and then you can assign the 'onclick' handler of a button to
+// opener.popup(width, height), where width and height are the values of the popup size;
+//
+// To use it, you would typically have code such as:
+// var myLoginCheckFunction = ... some AJAXy call or page refresh operation
+// that will cause the user to see the logged-in experience in the current page.
+// var openidParams = { realm : 'openid.realm', returnToUrl : 'openid.return_to',
+// opEndpoint : 'openid.op_endpoint', onCloseHandler : myLoginCheckFunction,
+// shouldEncodeUrls : 'true' (default) or 'false', extensions : myOpenIDExtensions };
+//
+// Here extensions include any OpenID extensions that you support. For instance,
+// if you support Attribute Exchange v.1.0, you can say:
+// (Example for attribute exchange request for email and name,
+// assuming that shouldEncodeUrls = 'true':)
+// var myOpenIDExtensions = {
+// 'openid.ax.ns' : 'http://openid.net/srv/ax/1.0',
+// 'openid.ax.type.email' : 'http://axschema.org/contact/email',
+// 'openid.ax.type.name1' : 'http://axschema.org/namePerson/first',
+// 'openid.ax.type.name2' : 'http://axschema.org/namePerson/last',
+// 'openid.ax.required' : 'email,name1,name2' };
+// Note that the 'ui' namespace is reserved by this library for the OpenID
+// UI extension, and that the mode 'popup' is automatically applied.
+// If you wish to make use of the 'language' feature of the OpenID UI extension
+// simply add the following entry (example assumes the language requested
+// is Swiss French:
+// var my OpenIDExtensions = {
+// ... // other extension parameters
+// 'openid.ui.language' : 'fr_CH',
+// ... };
+popupManager.createPopupOpener = (function(openidParams) {
+ var interval_ = null;
+ var popupWindow_ = null;
+ var that = this;
+ var shouldEscape_ = ('shouldEncodeUrls' in openidParams) ? openidParams.shouldEncodeUrls : true;
+ var encodeIfRequested_ = function(url) {
+ return (shouldEscape_ ? encodeURIComponent(url) : url);
+ };
+ var identifier_ = ('identifier' in openidParams) ? encodeIfRequested_(openidParams.identifier) :
+ this.constants.openidSpec.identifier_select;
+ var identity_ = ('identity' in openidParams) ? encodeIfRequested_(openidParams.identity) :
+ this.constants.openidSpec.identifier_select;
+ var openidNs_ = ('namespace' in openidParams) ? encodeIfRequested_(openidParams.namespace) :
+ this.constants.openidSpec.namespace2;
+ var onOpenHandler_ = (('onOpenHandler' in openidParams) &&
+ ('function' === typeof(openidParams.onOpenHandler))) ?
+ openidParams.onOpenHandler : this.darkenScreen;
+ var onCloseHandler_ = (('onCloseHandler' in openidParams) &&
+ ('function' === typeof(openidParams.onCloseHandler))) ?
+ openidParams.onCloseHandler : null;
+ var returnToUrl_ = ('returnToUrl' in openidParams) ? openidParams.returnToUrl : null;
+ var realm_ = ('realm' in openidParams) ? openidParams.realm : null;
+ var endpoint_ = ('opEndpoint' in openidParams) ? openidParams.opEndpoint : null;
+ var extensions_ = ('extensions' in openidParams) ? openidParams.extensions : null;
+
+ // processes key value pairs, escaping any input;
+ var keyValueConcat_ = function(keyValuePairs) {
+ var result = "";
+ for (key in keyValuePairs) {
+ result += ['&', key, '=', encodeIfRequested_(keyValuePairs[key])].join('');
+ }
+ return result;
+ };
+
+ //Assembles the OpenID request from customizable parameters
+ var buildUrlToOpen_ = function() {
+ var connector = '&';
+ var encodedUrl = null;
+ var urlToOpen = null;
+ if ((null === endpoint_) || (null === returnToUrl_)) {
+ return;
+ }
+ if (endpoint_.indexOf('?') === -1) {
+ connector = '?';
+ }
+ encodedUrl = encodeIfRequested_(returnToUrl_);
+ urlToOpen = [ endpoint_, connector,
+ 'openid.ns=', openidNs_,
+ '&openid.mode=checkid_setup',
+ '&openid.claimed_id=', identifier_,
+ '&openid.identity=', identity_,
+ '&openid.return_to=', encodedUrl ].join('');
+ if (realm_ !== null) {
+ urlToOpen += "&openid.realm=" + encodeIfRequested_(realm_);
+ }
+ if (extensions_ !== null) {
+ urlToOpen += keyValueConcat_(extensions_);
+ }
+ urlToOpen += '&openid.ns.ui=' + encodeURIComponent(
+ 'http://specs.openid.net/extensions/ui/1.0');
+ urlToOpen += '&openid.ui.mode=popup';
+ return urlToOpen;
+ };
+
+ // Tests that the popup window has closed
+ var isPopupClosed_ = function() {
+ return (!popupWindow_ || popupWindow_.closed);
+ };
+
+ // Check to perform at each execution of the timed loop. It also triggers
+ // the action that follows the closing of the popup
+ var waitForPopupClose_ = function() {
+ if (isPopupClosed_()) {
+ popupWindow_ = null;
+ var darkCover = window.document.getElementById(window.popupManager.constants['darkCover']);
+ if (darkCover) {
+ darkCover.style.visibility = 'hidden';
+ }
+ if (onCloseHandler_ !== null) {
+ onCloseHandler_();
+ }
+ if ((null !== interval_)) {
+ window.clearInterval(interval_);
+ interval_ = null;
+ }
+ }
+ };
+
+ return {
+ // Function that opens the window.
+ popup: function(width, height) {
+ var urlToOpen = buildUrlToOpen_();
+ if (onOpenHandler_ !== null) {
+ onOpenHandler_();
+ }
+ var coordinates = that.getCenteredCoords(width, height);
+ popupWindow_ = window.open(urlToOpen, "",
+ "width=" + width + ",height=" + height +
+ ",status=1,location=1,resizable=yes" +
+ ",left=" + coordinates[0] +",top=" + coordinates[1]);
+ interval_ = window.setInterval(waitForPopupClose_, 80);
+ return true;
+ }
+ };
+});