summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--3rdparty/OAuth/LICENSE.TXT21
-rw-r--r--3rdparty/OAuth/OAuth.php895
m---------3rdparty/Symfony/Component/Routing0
-rw-r--r--db_structure.xml149
-rw-r--r--lib/api.php253
-rw-r--r--[-rwxr-xr-x]lib/app.php14
-rw-r--r--lib/base.php51
-rw-r--r--lib/oauth/server.php111
-rw-r--r--lib/oauth/store.php95
-rw-r--r--lib/ocs.php123
-rw-r--r--lib/ocs/activity.php8
-rw-r--r--lib/ocs/cloud.php96
-rw-r--r--lib/ocs/config.php13
-rw-r--r--lib/ocs/person.php20
-rw-r--r--lib/ocs/privatedata.php44
-rw-r--r--lib/public/api.php42
-rw-r--r--lib/route.php65
-rw-r--r--lib/router.php76
-rw-r--r--ocs/routes.php23
-rw-r--r--ocs/v1.php15
-rw-r--r--settings/css/oauth.css4
-rw-r--r--settings/oauth.php98
-rw-r--r--settings/templates/oauth-required-apps.php19
-rw-r--r--settings/templates/oauth.php20
25 files changed, 2134 insertions, 124 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000000..0f4ad588071
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "3rdparty/Symfony/Component/Routing"]
+ path = 3rdparty/Symfony/Component/Routing
+ url = git://github.com/symfony/Routing.git
diff --git a/3rdparty/OAuth/LICENSE.TXT b/3rdparty/OAuth/LICENSE.TXT
new file mode 100644
index 00000000000..8891c7ddc90
--- /dev/null
+++ b/3rdparty/OAuth/LICENSE.TXT
@@ -0,0 +1,21 @@
+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/3rdparty/OAuth/OAuth.php b/3rdparty/OAuth/OAuth.php
new file mode 100644
index 00000000000..64b7007ab9d
--- /dev/null
+++ b/3rdparty/OAuth/OAuth.php
@@ -0,0 +1,895 @@
+<?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);
+
+ // Check for zero length, although unlikely here
+ if (strlen($built) == 0 || strlen($signature) == 0) {
+ return false;
+ }
+
+ if (strlen($built) != strlen($signature)) {
+ return false;
+ }
+
+ // Avoid a timing leak with a (hopefully) time insensitive compare
+ $result = 0;
+ for ($i = 0; $i < strlen($signature); $i++) {
+ $result |= ord($built{$i}) ^ ord($signature{$i});
+ }
+
+ return $result == 0;
+ }
+}
+
+/**
+ * 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['SERVER_NAME'] .
+ ':' .
+ $_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'])) ? strtolower($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);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/3rdparty/Symfony/Component/Routing b/3rdparty/Symfony/Component/Routing
new file mode 160000
+Subproject d72483890880a987afa679503af096d2aaf7d2e
diff --git a/db_structure.xml b/db_structure.xml
index 2256dff943c..43add8d52ea 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -450,6 +450,155 @@
</declaration>
</table>
+
+ <table>
+
+ <name>*dbprefix*oauth_consumers</name>
+
+ <declaration>
+
+ <field>
+ <name>key</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>secret</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>callback_success</name>
+ <type>text</type>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>callback_fail</name>
+ <type>text</type>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>name</name>
+ <type>text</type>
+ <length>200</length>
+ </field>
+
+ <field>
+ <name>url</name>
+ <type>text</type>
+ <length>255</length>
+ </field>
+
+
+ </declaration>
+
+ </table>
+
+ <table>
+
+ <name>*dbprefix*oauth_nonce</name>
+
+ <declaration>
+
+ <field>
+ <name>consumer_key</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>token</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>timestamp</name>
+ <type>integer</type>
+ <length>11</length>
+ </field>
+
+ <field>
+ <name>nonce</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+
+ </declaration>
+
+ </table>
+
+ <table>
+
+ <name>*dbprefix*oauth_scopes</name>
+
+ <declaration>
+
+ <field>
+ <name>key</name>
+ <type>text</type>
+ <length>40</length>
+ </field>
+
+ <field>
+ <name>type</name>
+ <type>text</type>
+ <length>7</length>
+ </field>
+
+ <field>
+ <name>scopes</name>
+ <type>text</type>
+ <length>255</length>
+ </field>
+
+ </declaration>
+
+ </table>
+
+ <table>
+
+ <name>*dbprefix*oauth_tokens</name>
+
+ <declaration>
+
+ <field>
+ <name>consumer_key</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>key</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>secret</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>type></name>
+ <type>text</type>
+ <length>7</length>
+ </field>
+
+ <field>
+ <name>authorised</name>
+ <type>boolean</type>
+ <default>0</default>
+ </field>
+
+ </declaration>
+
+ </table>
<table>
diff --git a/lib/api.php b/lib/api.php
new file mode 100644
index 00000000000..29403030233
--- /dev/null
+++ b/lib/api.php
@@ -0,0 +1,253 @@
+<?php
+/**
+* ownCloud
+*
+* @author Tom Needham
+* @author Michael Gapczynski
+* @author Bart Visscher
+* @copyright 2012 Tom Needham tom@owncloud.com
+* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
+* @copyright 2012 Bart Visscher bartv@thisnet.nl
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+class OC_API {
+
+ /**
+ * API authentication levels
+ */
+ const GUEST_AUTH = 0;
+ const USER_AUTH = 1;
+ const SUBADMIN_AUTH = 2;
+ const ADMIN_AUTH = 3;
+
+ private static $server;
+
+ /**
+ * initialises the OAuth store and server
+ */
+ private static function init() {
+ self::$server = new OC_OAuth_Server(new OC_OAuth_Store());
+ }
+
+ /**
+ * api actions
+ */
+ protected static $actions = array();
+
+ /**
+ * registers an api call
+ * @param string $method the http method
+ * @param string $url the url to match
+ * @param callable $action the function to run
+ * @param string $app the id of the app registering the call
+ * @param int $authlevel the level of authentication required for the call
+ * @param array $defaults
+ * @param array $requirements
+ */
+ public static function register($method, $url, $action, $app,
+ $authlevel = OC_API::USER_AUTH,
+ $defaults = array(),
+ $requirements = array()){
+ $name = strtolower($method).$url;
+ $name = str_replace(array('/', '{', '}'), '_', $name);
+ if(!isset(self::$actions[$name])){
+ OC::getRouter()->useCollection('ocs');
+ OC::getRouter()->create($name, $url.'.{_format}')
+ ->method($method)
+ ->defaults(array('_format' => 'xml') + $defaults)
+ ->requirements(array('_format' => 'xml|json') + $requirements)
+ ->action('OC_API', 'call');
+ self::$actions[$name] = array();
+ }
+ self::$actions[$name][] = array('app' => $app, 'action' => $action, 'authlevel' => $authlevel);
+ }
+
+ /**
+ * handles an api call
+ * @param array $parameters
+ */
+ public static function call($parameters){
+ // Prepare the request variables
+ if($_SERVER['REQUEST_METHOD'] == 'PUT'){
+ parse_str(file_get_contents("php://input"), $_PUT);
+ } else if($_SERVER['REQUEST_METHOD'] == 'DELETE'){
+ parse_str(file_get_contents("php://input"), $_DELETE);
+ }
+ $name = $parameters['_route'];
+ // Loop through registered actions
+ foreach(self::$actions[$name] as $action){
+ $app = $action['app'];
+ // Authorsie this call
+ if(self::isAuthorised($action)){
+ if(is_callable($action['action'])){
+ $responses[] = array('app' => $app, 'response' => call_user_func($action['action'], $parameters));
+ } else {
+ $responses[] = array('app' => $app, 'response' => 501);
+ }
+ } else {
+ $responses[] = array('app' => $app, 'response' => 401);
+ }
+
+ }
+ // Merge the responses
+ $response = self::mergeResponses($responses);
+ // Send the response
+ if(isset($parameters['_format'])){
+ self::respond($response, $parameters['_format']);
+ } else {
+ self::respond($response);
+ }
+ // logout the user to be stateless
+ OC_User::logout();
+ }
+
+ /**
+ * authenticate the api call
+ * @param array $action the action details as supplied to OC_API::register()
+ * @return bool
+ */
+ private static function isAuthorised($action){
+ $level = $action['authlevel'];
+ switch($level){
+ case OC_API::GUEST_AUTH:
+ // Anyone can access
+ return true;
+ break;
+ case OC_API::USER_AUTH:
+ // User required
+ return self::loginUser();
+ break;
+ case OC_API::SUBADMIN_AUTH:
+ // Check for subadmin
+ $user = self::loginUser();
+ if(!$user){
+ return false;
+ } else {
+ $subadmin = OC_SubAdmin::isSubAdmin($user);
+ $admin = OC_Group::inGroup($user, 'admin');
+ if($subadmin || $admin){
+ return true;
+ } else {
+ return false;
+ }
+ }
+ break;
+ case OC_API::ADMIN_AUTH:
+ // Check for admin
+ $user = self::loginUser();
+ if(!$user){
+ return false;
+ } else {
+ return OC_Group::inGroup($user, 'admin');
+ }
+ break;
+ default:
+ // oops looks like invalid level supplied
+ return false;
+ break;
+ }
+ }
+
+ /**
+ * http basic auth
+ * @return string|false (username, or false on failure)
+ */
+ private static function loginUser(){
+ $authuser = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
+ $authpw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
+ return OC_User::login($authuser, $authpw) ? $authuser : false;
+ }
+
+ /**
+ * intelligently merges the different responses
+ * @param array $responses
+ * @return array the final merged response
+ */
+ private static function mergeResponses($responses){
+ $finalresponse = array(
+ 'meta' => array(
+ 'statuscode' => '',
+ ),
+ 'data' => array(),
+ );
+ $numresponses = count($responses);
+
+ foreach($responses as $response){
+ if(is_int($response['response']) && empty($finalresponse['meta']['statuscode'])){
+ $finalresponse['meta']['statuscode'] = $response['response'];
+ continue;
+ }
+ if(is_array($response['response'])){
+ // Shipped apps win
+ if(OC_App::isShipped($response['app'])){
+ $finalresponse['data'] = array_merge_recursive($finalresponse['data'], $response['response']);
+ } else {
+ $finalresponse['data'] = array_merge_recursive($response['response'], $finalresponse['data']);
+ }
+ $finalresponse['meta']['statuscode'] = 100;
+ }
+ }
+ //Some tidying up
+ if($finalresponse['meta']['statuscode']=='100'){
+ $finalresponse['meta']['status'] = 'ok';
+ } else {
+ $finalresponse['meta']['status'] = 'failure';
+ }
+ if(empty($finalresponse['data'])){
+ unset($finalresponse['data']);
+ }
+ return array('ocs' => $finalresponse);
+ }
+
+ /**
+ * respond to a call
+ * @param int|array $response the response
+ * @param string $format the format xml|json
+ */
+ private static function respond($response, $format='json'){
+ if ($format == 'json') {
+ OC_JSON::encodedPrint($response);
+ } else if ($format == 'xml') {
+ header('Content-type: text/xml; charset=UTF-8');
+ $writer = new XMLWriter();
+ $writer->openMemory();
+ $writer->setIndent( true );
+ $writer->startDocument();
+ self::toXML($response, $writer);
+ $writer->endDocument();
+ echo $writer->outputMemory(true);
+ } else {
+ var_dump($format, $response);
+ }
+ }
+
+ private static function toXML($array, $writer){
+ foreach($array as $k => $v) {
+ if (is_numeric($k)) {
+ $k = 'element';
+ }
+ if (is_array($v)) {
+ $writer->startElement($k);
+ self::toXML($v, $writer);
+ $writer->endElement();
+ } else {
+ $writer->writeElement($k, $v);
+ }
+ }
+ }
+
+}
diff --git a/lib/app.php b/lib/app.php
index 28f1f16ebaf..620732f6006 100755..100644
--- a/lib/app.php
+++ b/lib/app.php
@@ -136,6 +136,20 @@ class OC_App{
OC_Appconfig::setValue($app, 'types', $appTypes);
}
+
+ /**
+ * check if app is shipped
+ * @param string $appid the id of the app to check
+ * @return bool
+ */
+ public static function isShipped($appid){
+ $info = self::getAppInfo($appid);
+ if(isset($info['shipped']) && $info['shipped']=='true'){
+ return true;
+ } else {
+ return false;
+ }
+ }
/**
* get all enabled apps
diff --git a/lib/base.php b/lib/base.php
index 6b4dd789b2f..2b05fd7f9ea 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -67,6 +67,10 @@ class OC{
* check if owncloud runs in cli mode
*/
public static $CLI = false;
+ /*
+ * OC router
+ */
+ protected static $router = null;
/**
* SPL autoload
*/
@@ -90,9 +94,13 @@ class OC{
elseif(strpos($className, 'Sabre_')===0) {
$path = str_replace('_', '/', $className) . '.php';
}
- elseif(strpos($className, 'Test_')===0) {
- $path = 'tests/lib/'.strtolower(str_replace('_', '/', substr($className, 5)) . '.php');
- }else{
+ elseif(strpos($className,'Symfony\\')===0){
+ $path = str_replace('\\','/',$className) . '.php';
+ }
+ elseif(strpos($className,'Test_')===0){
+ $path = 'tests/lib/'.strtolower(str_replace('_','/',substr($className,5)) . '.php');
+
+ } else {
return false;
}
@@ -262,7 +270,42 @@ class OC{
session_start();
}
- public static function init() {
+ public static function loadapp(){
+ if(file_exists(OC_App::getAppPath(OC::$REQUESTEDAPP) . '/index.php')){
+ require_once(OC_App::getAppPath(OC::$REQUESTEDAPP) . '/index.php');
+ }else{
+ trigger_error('The requested App was not found.', E_USER_ERROR);//load default app instead?
+ }
+ }
+
+ public static function loadfile(){
+ if(file_exists(OC_App::getAppPath(OC::$REQUESTEDAPP) . '/' . OC::$REQUESTEDFILE)){
+ if(substr(OC::$REQUESTEDFILE, -3) == 'css'){
+ $file = OC_App::getAppWebPath(OC::$REQUESTEDAPP). '/' . OC::$REQUESTEDFILE;
+ $minimizer = new OC_Minimizer_CSS();
+ $minimizer->output(array(array(OC_App::getAppPath(OC::$REQUESTEDAPP), OC_App::getAppWebPath(OC::$REQUESTEDAPP), OC::$REQUESTEDFILE)),$file);
+ exit;
+ }elseif(substr(OC::$REQUESTEDFILE, -3) == 'php'){
+ require_once(OC_App::getAppPath(OC::$REQUESTEDAPP). '/' . OC::$REQUESTEDFILE);
+ }
+ }else{
+ die();
+ header('HTTP/1.0 404 Not Found');
+ exit;
+ }
+ }
+
+ public static function getRouter() {
+ if (!isset(OC::$router)) {
+ OC::$router = new OC_Router();
+ OC::$router->loadRoutes();
+ }
+
+ return OC::$router;
+ }
+
+ public static function init(){
+
// register autoloader
spl_autoload_register(array('OC','autoload'));
setlocale(LC_ALL, 'en_US.UTF-8');
diff --git a/lib/oauth/server.php b/lib/oauth/server.php
new file mode 100644
index 00000000000..a82a1e2fb0e
--- /dev/null
+++ b/lib/oauth/server.php
@@ -0,0 +1,111 @@
+<?php
+/**
+* ownCloud
+*
+* @author Tom Needham
+* @author Michael Gapczynski
+* @copyright 2012 Tom Needham tom@owncloud.com
+* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+require_once(OC::$THIRDPARTYROOT.'/3rdparty/OAuth/OAuth.php');
+
+class OC_OAuth_Server extends OAuthServer {
+
+ /**
+ * sets up the server object
+ */
+ public static function init(){
+ $server = new OC_OAuth_Server(new OC_OAuth_Store());
+ $server->add_signature_method(new OAuthSignatureMethod_HMAC_SHA1());
+ return $server;
+ }
+
+ public function get_request_token(&$request){
+ // Check the signature
+ $token = $this->fetch_request_token($request);
+ $scopes = $request->get_parameter('scopes');
+ // Add scopes to request token
+ $this->saveScopes($token, $scopes);
+
+ return $token;
+ }
+
+ public function saveScopes($token, $scopes){
+ $query = OC_DB::prepare("INSERT INTO `*PREFIX*oauth_scopes` (`key`, `scopes`) VALUES (?, ?)");
+ $result = $query->execute(array($token->key, $scopes));
+ }
+
+
+ /**
+ * authorises a request token
+ * @param string $request the request token to authorise
+ * @return What does it return?
+ */
+ public function authoriseRequestToken(&$request) {
+ $this->get_version($request);
+ $consumer = $this->get_consumer($request);
+ $this->check_signature($request, $consumer, null);
+ $token = $this->get_token($request, $consumer, 'request');
+ $this->check_signature($request, $consumer, $token);
+ return $this->data_store->authorise_request_token($token, $consumer, OC_User::getUser());
+ }
+
+ /**
+ * checks if request is authorised
+ * TODO distinguish between failures as one is a 400 error and other is 401
+ * @return string|int
+ */
+ public static function isAuthorised($scope) {
+ try {
+ $request = OAuthRequest::from_request();
+ //$this->verify_request(); // TODO cannot use $this in static context
+ return true;
+ } catch (OAuthException $exception) {
+ return false;
+ }
+ // TODO Get user out of token? May have to write own verify_request()
+// $run = true;
+// OC_Hook::emit( "OC_User", "pre_login", array( "run" => &$run, "uid" => $user ));
+// if(!$run){
+// return false;
+// }
+// OC_User::setUserId($user);
+// OC_Hook::emit( "OC_User", "post_login", array( "uid" => $user ));
+// return $user;
+ }
+
+ /**
+ * registers a consumer with the ownCloud Instance
+ * @param string $name the name of the external app
+ * @param string $url the url to find out more info on the external app
+ * @param string $callbacksuccess the url to redirect to after autorisation success
+ * @param string $callbackfail the url to redirect to if the user does not authorise the application
+ * @return false|OAuthConsumer object
+ */
+ static function register_consumer($name, $url, $callbacksuccess=null, $callbackfail=null){
+ // TODO validation
+ // Check callback url is outside of ownCloud for security
+ // Generate key and secret
+ $key = sha1(md5(uniqid(rand(), true)));
+ $secret = sha1(md5(uniqid(rand(), true)));
+ $query = OC_DB::prepare("INSERT INTO `*PREFIX*oauth_consumers` (`key`, `secret`, `name`, `url`, `callback_success`, `callback_fail`) VALUES (?, ?, ?, ?, ?, ?)");
+ $result = $query->execute(array($key, $secret, $name, $url, $callbacksuccess, $callbackfail));
+ return new OAuthConsumer($key, $secret, $callbacksuccess);
+ }
+
+} \ No newline at end of file
diff --git a/lib/oauth/store.php b/lib/oauth/store.php
new file mode 100644
index 00000000000..aa68d38957d
--- /dev/null
+++ b/lib/oauth/store.php
@@ -0,0 +1,95 @@
+<?php
+/**
+* ownCloud
+*
+* @author Michael Gapczynski
+* @author Tom Needham
+* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
+* @copyright 2012 Tom Needham tom@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+class OC_OAuth_Store extends OAuthDataStore {
+
+ static private $MAX_TIMESTAMP_DIFFERENCE = 300;
+
+ function lookup_consumer($consumer_key) {
+ $query = OC_DB::prepare("SELECT `key`, `secret`, `callback_success` FROM `*PREFIX*oauth_consumers` WHERE `key` = ?");
+ $results = $query->execute(array($consumer_key));
+ if($results->numRows()==0){
+ return NULL;
+ } else {
+ $details = $results->fetchRow();
+ $callback = !empty($details['callback_success']) ? $details['callback_success'] : NULL;
+ return new OAuthConsumer($details['key'], $details['secret'], $callback);
+ }
+ }
+
+ function lookup_token($consumer, $token_type, $token) {
+ $query = OC_DB::prepare("SELECT `key`, `secret`, `type` FROM `*PREFIX*oauth_tokens` WHERE `consumer_key` = ? AND `key` = ? AND `type` = ?");
+ $results = $query->execute(array($consumer->key, $token->key, $token_type));
+ if($results->numRows()==0){
+ return NULL;
+ } else {
+ $token = $results->fetchRow();
+ return new OAuthToken($token['key'], $token['secret']);
+ }
+ }
+
+ function lookup_nonce($consumer, $token, $nonce, $timestamp) {
+ $query = OC_DB::prepare("INSERT INTO `*PREFIX*oauth_nonce` (`consumer_key`, `token`, `timestamp`, `nonce`) VALUES (?, ?, ?, ?)");
+ $affectedrows = $query->execute(array($consumer->key, $token, $timestamp, $nonce));
+ // Delete all timestamps older than the one passed
+ $query = OC_DB::prepare("DELETE FROM `*PREFIX*oauth_nonce` WHERE `consumer_key` = ? AND `token` = ? AND `timestamp` < ?");
+ $result = $query->exec(array($consumer->key, $token, $timestamp - self::$MAX_TIMESTAMP_DIFFERENCE));
+ return $result;
+ }
+
+ function new_token($consumer, $token_type) {
+ $key = md5(time());
+ $secret = time() + time();
+ $token = new OAuthToken($key, md5(md5($secret)));
+ $query = OC_DB::prepare("INSERT INTO `*PREFIX*oauth_tokens` (`consumer_key`, `key`, `secret`, `type`, `timestamp`) VALUES (?, ?, ?, ?, ?, ?)");
+ $result = $query->execute(array($consumer->key, $key, $secret, $token_type, time()));
+ return $token;
+ }
+
+ function new_request_token($consumer, $callback = null) {
+ return $this->new_token($consumer, 'request');
+ }
+
+ function authorise_request_token($token, $consumer, $uid) {
+ $query = OC_DB::prepare("UPDATE `*PREFIX*oauth_tokens` SET uid = ? WHERE `consumer_key` = ? AND `key` = ? AND `type` = ?");
+ $query->execute(array($uid, $consumer->key, $token->key, 'request'));
+ // TODO Return oauth_verifier
+ }
+
+ function new_access_token($token, $consumer, $verifier = null) {
+ $query = OC_DB::prepare("SELECT `timestamp`, `scope` FROM `*PREFIX*oauth_tokens` WHERE `consumer_key` = ? AND `key` = ? AND `type` = ?");
+ $result = $query->execute(array($consumer->key, $token->key, 'request'))->fetchRow();
+ if (isset($result['timestamp'])) {
+ if ($timestamp + self::MAX_REQUEST_TOKEN_TTL < time()) {
+ return false;
+ }
+ $accessToken = $this->new_token($consumer, 'access', $result['scope']);
+ }
+ // Delete request token
+ $query = OC_DB::prepare("DELETE FROM `*PREFIX*oauth_tokens` WHERE `key` = ? AND `type` = ?");
+ $query->execute(array($token->key, 'request'));
+ return $accessToken;
+ }
+
+} \ No newline at end of file
diff --git a/lib/ocs.php b/lib/ocs.php
index 7350c3c8821..1cec3ecc7c0 100644
--- a/lib/ocs.php
+++ b/lib/ocs.php
@@ -23,8 +23,6 @@
*
*/
-
-
/**
* Class to handle open collaboration services API requests
*
@@ -72,14 +70,7 @@ class OC_OCS {
}
}
- /**
- main function to handle the REST request
- **/
- public static function handle() {
- // overwrite the 404 error page returncode
- header("HTTP/1.0 200 OK");
-
-
+ public static function notFound() {
if($_SERVER['REQUEST_METHOD'] == 'GET') {
$method='get';
}elseif($_SERVER['REQUEST_METHOD'] == 'PUT') {
@@ -91,114 +82,11 @@ class OC_OCS {
echo('internal server error: method not supported');
exit();
}
-
- // preprocess url
- $url = strtolower($_SERVER['REQUEST_URI']);
- if(substr($url, (strlen($url)-1))<>'/') $url.='/';
- $ex=explode('/', $url);
- $paracount=count($ex);
$format = self::readData($method, 'format', 'text', '');
+ $txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
+ $txt.=OC_OCS::getDebugOutput();
+ echo(OC_OCS::generateXml($format,'failed',999,$txt));
- // eventhandler
- // CONFIG
- // apiconfig - GET - CONFIG
- if(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'config')) {
- OC_OCS::apiconfig($format);
-
- // PERSON
- // personcheck - POST - PERSON/CHECK
- } elseif(($method=='post') and ($ex[$paracount-4] == 'v1.php') and ($ex[$paracount-3]=='person') and ($ex[$paracount-2] == 'check')) {
- $login = self::readData($method, 'login', 'text');
- $passwd = self::readData($method, 'password', 'text');
- OC_OCS::personcheck($format, $login, $passwd);
-
- // ACTIVITY
- // activityget - GET ACTIVITY page,pagesize als urlparameter
- }elseif(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'activity')) {
- $page = self::readData($method, 'page', 'int', 0);
- $pagesize = self::readData($method, 'pagesize', 'int', 10);
- if($pagesize<1 or $pagesize>100) $pagesize=10;
- OC_OCS::activityget($format, $page, $pagesize);
-
- // activityput - POST ACTIVITY
- }elseif(($method=='post') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'activity')) {
- $message = self::readData($method, 'message', 'text');
- OC_OCS::activityput($format, $message);
-
-
- // PRIVATEDATA
- // get - GET DATA
- }elseif(($method=='get') and ($ex[$paracount-4] == 'v1.php') and ($ex[$paracount-2] == 'getattribute')) {
- OC_OCS::privateDataGet($format);
-
- }elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-3] == 'getattribute')) {
- $app=$ex[$paracount-2];
- OC_OCS::privateDataGet($format, $app);
- }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'getattribute')) {
-
- $key=$ex[$paracount-2];
- $app=$ex[$paracount-3];
- OC_OCS::privateDataGet($format, $app, $key);
-
- // set - POST DATA
- }elseif(($method=='post') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'setattribute')) {
- $key=$ex[$paracount-2];
- $app=$ex[$paracount-3];
- $value = self::readData($method, 'value', 'text');
- OC_OCS::privatedataset($format, $app, $key, $value);
- // delete - POST DATA
- }elseif(($method=='post') and ($ex[$paracount-6] =='v1.php') and ($ex[$paracount-4] == 'deleteattribute')) {
- $key=$ex[$paracount-2];
- $app=$ex[$paracount-3];
- OC_OCS::privatedatadelete($format, $app, $key);
-
- // CLOUD
- // systemWebApps
- }elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-4]=='cloud') and ($ex[$paracount-3] == 'system') and ($ex[$paracount-2] == 'webapps')) {
- OC_OCS::systemwebapps($format);
-
- // quotaget
- }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'quota')) {
- $user=$ex[$paracount-3];
- OC_OCS::quotaget($format, $user);
-
- // quotaset
- }elseif(($method=='post') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'quota')) {
- $user=$ex[$paracount-3];
- $quota = self::readData('post', 'quota', 'int');
- OC_OCS::quotaset($format, $user, $quota);
-
- // keygetpublic
- }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'publickey')) {
- $user=$ex[$paracount-3];
- OC_OCS::publicKeyGet($format, $user);
-
- // keygetprivate
- }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'privatekey')) {
- $user=$ex[$paracount-3];
- OC_OCS::privateKeyGet($format, $user);
-
-
-// add more calls here
-// please document all the call in the draft spec
-// http://www.freedesktop.org/wiki/Specifications/open-collaboration-services-1.7#CLOUD
-
-// TODO:
-// users
-// groups
-// bookmarks
-// sharing
-// versioning
-// news (rss)
-
-
-
- }else{
- $txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
- $txt.=OC_OCS::getdebugoutput();
- echo(OC_OCS::generatexml($format, 'failed', 999, $txt));
- }
- exit();
}
/**
@@ -378,7 +266,8 @@ class OC_OCS {
* @param string $format
* @return string xml/json
*/
- private static function apiConfig($format) {
+ public static function apiConfig($parameters) {
+ $format = $parameters['format'];
$user=OC_OCS::checkpassword(false);
$url=substr(OCP\Util::getServerHost().$_SERVER['SCRIPT_NAME'], 0, -11).'';
diff --git a/lib/ocs/activity.php b/lib/ocs/activity.php
new file mode 100644
index 00000000000..07b571665ec
--- /dev/null
+++ b/lib/ocs/activity.php
@@ -0,0 +1,8 @@
+<?php
+
+class OC_OCS_Activity {
+
+ public static function activityGet($parameters){
+ // TODO
+ }
+}
diff --git a/lib/ocs/cloud.php b/lib/ocs/cloud.php
new file mode 100644
index 00000000000..2f2aad714a3
--- /dev/null
+++ b/lib/ocs/cloud.php
@@ -0,0 +1,96 @@
+<?php
+
+class OC_OCS_Cloud {
+
+ public static function getSystemWebApps($parameters){
+ OC_Util::checkLoggedIn();
+ $apps = OC_App::getEnabledApps();
+ $values = array();
+ foreach($apps as $app) {
+ $info = OC_App::getAppInfo($app);
+ if(isset($info['standalone'])) {
+ $newvalue = array('name'=>$info['name'],'url'=>OC_Helper::linkToAbsolute($app,''),'icon'=>'');
+ $values[] = $newvalue;
+ }
+ }
+ return $values;
+ }
+
+ public static function getUserQuota($parameters){
+ OC_Util::checkLoggedIn();
+ $user = OC_User::getUser();
+ if(OC_Group::inGroup($user, 'admin') or ($user==$parameters['user'])) {
+
+ if(OC_User::userExists($parameters['user'])){
+ // calculate the disc space
+ $user_dir = '/'.$parameters['user'].'/files';
+ OC_Filesystem::init($user_dir);
+ $rootInfo=OC_FileCache::get('');
+ $sharedInfo=OC_FileCache::get('/Shared');
+ $used=$rootInfo['size']-$sharedInfo['size'];
+ $free=OC_Filesystem::free_space();
+ $total=$free+$used;
+ if($total==0) $total=1; // prevent division by zero
+ $relative=round(($used/$total)*10000)/100;
+
+ $xml=array();
+ $xml['quota']=$total;
+ $xml['free']=$free;
+ $xml['used']=$used;
+ $xml['relative']=$relative;
+
+ return $xml;
+ }else{
+ return 300;
+ }
+ }else{
+ return 300;
+ }
+ }
+
+ public static function setUserQuota($parameters){
+ OC_Util::checkLoggedIn();
+ $user = OC_User::getUser();
+ if(OC_Group::inGroup($user, 'admin')) {
+
+ // todo
+ // not yet implemented
+ // add logic here
+ error_log('OCS call: user:'.$parameters['user'].' quota:'.$parameters['quota']);
+
+ $xml=array();
+ return $xml;
+ }else{
+ return 300;
+ }
+ }
+
+ public static function getUserPublickey($parameters){
+ OC_Util::checkLoggedIn();
+
+ if(OC_User::userExists($parameters['user'])){
+ // calculate the disc space
+ // TODO
+ return array();
+ }else{
+ return 300;
+ }
+ }
+
+ public static function getUserPrivatekey($parameters){
+ OC_Util::checkLoggedIn();
+ $user = OC_User::getUser();
+ if(OC_Group::inGroup($user, 'admin') or ($user==$parameters['user'])) {
+
+ if(OC_User::userExists($user)){
+ // calculate the disc space
+ $txt='this is the private key of '.$parameters['user'];
+ echo($txt);
+ }else{
+ echo self::generateXml('', 'fail', 300, 'User does not exist');
+ }
+ }else{
+ echo self::generateXml('', 'fail', 300, 'You donĀ“t have permission to access this ressource.');
+ }
+ }
+}
diff --git a/lib/ocs/config.php b/lib/ocs/config.php
new file mode 100644
index 00000000000..06103cbeb4f
--- /dev/null
+++ b/lib/ocs/config.php
@@ -0,0 +1,13 @@
+<?php
+
+class OC_OCS_Config {
+
+ public static function apiConfig($parameters){
+ $xml['version'] = '1.7';
+ $xml['website'] = 'ownCloud';
+ $xml['host'] = OCP\Util::getServerHost();
+ $xml['contact'] = '';
+ $xml['ssl'] = 'false';
+ return $xml;
+ }
+}
diff --git a/lib/ocs/person.php b/lib/ocs/person.php
new file mode 100644
index 00000000000..23b8853533d
--- /dev/null
+++ b/lib/ocs/person.php
@@ -0,0 +1,20 @@
+<?php
+
+class OC_OCS_Person {
+
+ public static function check($parameters){
+ $login = isset($_POST['login']) ? $_POST['login'] : false;
+ $password = isset($_POST['password']) ? $_POST['password'] : false;
+ if($login && $password){
+ if(OC_User::checkPassword($login,$password)){
+ $xml['person']['personid'] = $login;
+ return $xml;
+ }else{
+ return 102;
+ }
+ }else{
+ return 101;
+ }
+ }
+
+}
diff --git a/lib/ocs/privatedata.php b/lib/ocs/privatedata.php
new file mode 100644
index 00000000000..1c781dece8a
--- /dev/null
+++ b/lib/ocs/privatedata.php
@@ -0,0 +1,44 @@
+<?php
+
+class OC_OCS_Privatedata {
+
+ public static function get($parameters){
+ OC_Util::checkLoggedIn();
+ $user = OC_User::getUser();
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ $result = OC_OCS::getData($user,$app,$key);
+ $xml= array();
+ foreach($result as $i=>$log) {
+ $xml[$i]['key']=$log['key'];
+ $xml[$i]['app']=$log['app'];
+ $xml[$i]['value']=$log['value'];
+ }
+ return $xml;
+ //TODO: replace 'privatedata' with 'attribute' once a new libattice has been released that works with it
+ }
+
+ public static function set($parameters){
+ OC_Util::checkLoggedIn();
+ $user = OC_User::getUser();
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ $value = OC_OCS::readData('post', 'value', 'text');
+ if(OC_OCS::setData($user,$app,$key,$value)){
+ return 100;
+ }
+ }
+
+ public static function delete($parameters){
+ OC_Util::checkLoggedIn();
+ $user = OC_User::getUser();
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ if($key=="" or $app==""){
+ return; //key and app are NOT optional here
+ }
+ if(OC_OCS::deleteData($user,$app,$key)){
+ return 100;
+ }
+ }
+}
diff --git a/lib/public/api.php b/lib/public/api.php
new file mode 100644
index 00000000000..2821554229b
--- /dev/null
+++ b/lib/public/api.php
@@ -0,0 +1,42 @@
+<?php
+/**
+* ownCloud
+*
+* @author Tom Needham
+* @copyright 2012 Tom Needham tom@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+namespace OCP;
+
+/**
+ * This class provides functions to manage apps in ownCloud
+ */
+class API {
+
+ /**
+ * registers an api call
+ * @param string $method the http method
+ * @param string $url the url to match
+ * @param callable $action the function to run
+ * @param string $app the id of the app registering the call
+ * @param int $authlevel the level of authentication required for the call (See OC_API constants)
+ */
+ public static function register($method, $url, $action, $app, $authlevel = OC_API::USER_AUTH){
+ \OC_API::register($method, $url, $action, $app, $authlevel);
+ }
+
+}
diff --git a/lib/route.php b/lib/route.php
new file mode 100644
index 00000000000..df3a18e844f
--- /dev/null
+++ b/lib/route.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+use Symfony\Component\Routing\Route;
+
+class OC_Route extends Route {
+ public function method($method) {
+ $this->setRequirement('_method', strtoupper($method));
+ return $this;
+ }
+
+ public function post() {
+ $this->method('POST');
+ return $this;
+ }
+
+ public function get() {
+ $this->method('GET');
+ return $this;
+ }
+
+ public function put() {
+ $this->method('PUT');
+ return $this;
+ }
+
+ public function delete() {
+ $this->method('DELETE');
+ return $this;
+ }
+
+ public function defaults($defaults) {
+ $action = $this->getDefault('action');
+ $this->setDefaults($defaults);
+ if (isset($defaults['action'])) {
+ $action = $defaults['action'];
+ }
+ $this->action($action);
+ return $this;
+ }
+
+ public function requirements($requirements) {
+ $method = $this->getRequirement('_method');
+ $this->setRequirements($requirements);
+ if (isset($requirements['_method'])) {
+ $method = $requirements['_method'];
+ }
+ $this->method($method);
+ return $this;
+ }
+
+ public function action($class, $function = null) {
+ $action = array($class, $function);
+ if (is_null($function)) {
+ $action = $class;
+ }
+ $this->setDefault('action', $action);
+ return $this;
+ }
+}
diff --git a/lib/router.php b/lib/router.php
new file mode 100644
index 00000000000..12cd55df414
--- /dev/null
+++ b/lib/router.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+use Symfony\Component\Routing\Matcher\UrlMatcher;
+use Symfony\Component\Routing\RequestContext;
+use Symfony\Component\Routing\RouteCollection;
+//use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+
+class OC_Router {
+ protected $collections = array();
+ protected $collection = null;
+ protected $root = null;
+
+ /**
+ * loads the api routes
+ */
+ public function loadRoutes() {
+ // TODO cache
+ $this->root = $this->getCollection('root');
+ foreach(OC_APP::getEnabledApps() as $app){
+ $file = OC_App::getAppPath($app).'/appinfo/routes.php';
+ if(file_exists($file)){
+ $this->useCollection($app);
+ require_once($file);
+ $collection = $this->getCollection($app);
+ $this->root->addCollection($collection, '/apps/'.$app);
+ }
+ }
+ // include ocs routes
+ require_once(OC::$SERVERROOT.'/ocs/routes.php');
+ $collection = $this->getCollection('ocs');
+ $this->root->addCollection($collection, '/ocs');
+ }
+
+ protected function getCollection($name) {
+ if (!isset($this->collections[$name])) {
+ $this->collections[$name] = new RouteCollection();
+ }
+ return $this->collections[$name];
+ }
+
+ public function useCollection($name) {
+ $this->collection = $this->getCollection($name);
+ }
+
+ public function create($name, $pattern, array $defaults = array(), array $requirements = array()) {
+ $route = new OC_Route($pattern, $defaults, $requirements);
+ $this->collection->add($name, $route);
+ return $route;
+ }
+
+ public function match($url) {
+ $context = new RequestContext($_SERVER['REQUEST_URI'], $_SERVER['REQUEST_METHOD']);
+ $matcher = new UrlMatcher($this->root, $context);
+ $parameters = $matcher->match($url);
+ if (isset($parameters['action'])) {
+ $action = $parameters['action'];
+ if (!is_callable($action)) {
+ var_dump($action);
+ throw new Exception('not a callable action');
+ }
+ unset($parameters['action']);
+ call_user_func($action, $parameters);
+ } elseif (isset($parameters['file'])) {
+ include ($parameters['file']);
+ } else {
+ throw new Exception('no action available');
+ }
+ }
+}
diff --git a/ocs/routes.php b/ocs/routes.php
new file mode 100644
index 00000000000..6b01abe31f2
--- /dev/null
+++ b/ocs/routes.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) 2012, Tom Needham <tom@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+// Config
+OC_API::register('get', '/config', array('OC_OCS_Config', 'apiConfig'), 'ocs', OC_API::GUEST_AUTH);
+// Person
+OC_API::register('post', '/person/check', array('OC_OCS_Person', 'check'), 'ocs', OC_API::GUEST_AUTH);
+// Activity
+OC_API::register('get', '/activity', array('OC_OCS_Activity', 'activityGet'), 'ocs', OC_API::USER_AUTH);
+// Privatedata
+OC_API::register('get', '/privatedata/getattribute', array('OC_OCS_Privatedata', 'get'), 'ocs', OC_API::USER_AUTH, array('app' => '', 'key' => ''));
+OC_API::register('get', '/privatedata/getattribute/{app}', array('OC_OCS_Privatedata', 'get'), 'ocs', OC_API::USER_AUTH, array('key' => ''));
+OC_API::register('get', '/privatedata/getattribute/{app}/{key}', array('OC_OCS_Privatedata', 'get'), 'ocs', OC_API::USER_AUTH);
+OC_API::register('post', '/privatedata/setattribute/{app}/{key}', array('OC_OCS_Privatedata', 'set'), 'ocs', OC_API::USER_AUTH);
+OC_API::register('post', '/privatedata/deleteattribute/{app}/{key}', array('OC_OCS_Privatedata', 'delete'), 'ocs', OC_API::USER_AUTH);
+// Cloud
+OC_API::register('get', '/cloud/system/webapps', array('OC_OCS_Cloud', 'getSystemWebApps'), 'ocs', OC_API::ADMIN_AUTH);
+
+?>
diff --git a/ocs/v1.php b/ocs/v1.php
index b12ea5ef18d..ac1312afb67 100644
--- a/ocs/v1.php
+++ b/ocs/v1.php
@@ -21,6 +21,15 @@
*
*/
-require_once '../lib/base.php';
-@ob_clean();
-OC_OCS::handle();
+require_once('../lib/base.php');
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Exception\MethodNotAllowedException;
+
+try {
+ OC::getRouter()->match('/ocs'.$_SERVER['PATH_INFO']);
+} catch (ResourceNotFoundException $e) {
+ OC_OCS::notFound();
+} catch (MethodNotAllowedException $e) {
+ OC_Response::setStatus(405);
+}
+
diff --git a/settings/css/oauth.css b/settings/css/oauth.css
new file mode 100644
index 00000000000..ccdb98cfa39
--- /dev/null
+++ b/settings/css/oauth.css
@@ -0,0 +1,4 @@
+.guest-container{ width:35%; margin: 2em auto 0 auto; }
+#oauth-request a.button{ float: right; }
+#oauth-request ul li{ list-style: disc; }
+#oauth-request ul { margin-left: 2em; margin-top: 1em; }
diff --git a/settings/oauth.php b/settings/oauth.php
new file mode 100644
index 00000000000..8dba9b33a53
--- /dev/null
+++ b/settings/oauth.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Copyright (c) 2012, Tom Needham <tom@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+require_once('../lib/base.php');
+// Logic
+$operation = isset($_GET['operation']) ? $_GET['operation'] : '';
+$server = OC_OAuth_server::init();
+
+switch($operation){
+
+ case 'register':
+
+ // Here external apps can register with an ownCloud
+ if(empty($_GET['name']) || empty($_GET['url'])){
+ // Invalid request
+ echo 401;
+ } else {
+ $callbacksuccess = empty($_GET['callback_success']) ? null : $_GET['callback_success'];
+ $callbackfail = empty($_GET['callback_fail']) ? null : $_GET['callback_fail'];
+ $consumer = OC_OAuth_Server::register_consumer($_GET['name'], $_GET['url'], $callbacksuccess, $callbackfail);
+
+ echo 'Registered consumer successfully! </br></br>Key: ' . $consumer->key . '</br>Secret: ' . $consumer->secret;
+ }
+ break;
+
+ case 'request_token':
+
+ try {
+ $request = OAuthRequest::from_request();
+ $token = $server->get_request_token($request);
+ echo $token;
+ } catch (OAuthException $exception) {
+ OC_Log::write('OC_OAuth_Server', $exception->getMessage(), OC_LOG::ERROR);
+ echo $exception->getMessage();
+ }
+
+ break;
+ case 'authorise';
+
+ OC_API::checkLoggedIn();
+ // Example
+ $consumer = array(
+ 'name' => 'Firefox Bookmark Sync',
+ 'scopes' => array('ookmarks'),
+ );
+
+ // Check that the scopes are real and installed
+ $apps = OC_App::getEnabledApps();
+ $notfound = array();
+ foreach($consumer['scopes'] as $requiredapp){
+ // App scopes are in this format: app_$appname
+ $requiredapp = end(explode('_', $requiredapp));
+ if(!in_array($requiredapp, $apps)){
+ $notfound[] = $requiredapp;
+ }
+ }
+ if(!empty($notfound)){
+ // We need more apps :( Show error
+ if(count($notfound)==1){
+ $message = 'requires that you have an extra app installed on your ownCloud. Please contact your ownCloud administrator and ask them to install the app below.';
+ } else {
+ $message = 'requires that you have some extra apps installed on your ownCloud. Please contract your ownCloud administrator and ask them to install the apps below.';
+ }
+ $t = new OC_Template('settings', 'oauth-required-apps', 'guest');
+ OC_Util::addStyle('settings', 'oauth');
+ $t->assign('requiredapps', $notfound);
+ $t->assign('consumer', $consumer);
+ $t->assign('message', $message);
+ $t->printPage();
+ } else {
+ $t = new OC_Template('settings', 'oauth', 'guest');
+ OC_Util::addStyle('settings', 'oauth');
+ $t->assign('consumer', $consumer);
+ $t->printPage();
+ }
+ break;
+
+ case 'access_token';
+ try {
+ $request = OAuthRequest::from_request();
+ $token = $server->fetch_access_token($request);
+ echo $token;
+ } catch (OAuthException $exception) {
+ OC_Log::write('OC_OAuth_Server', $exception->getMessage(), OC_LOG::ERROR);
+ echo $exception->getMessage();
+ }
+
+ break;
+ default:
+ // Something went wrong, we need an operation!
+ OC_Response::setStatus(400);
+ break;
+
+}
diff --git a/settings/templates/oauth-required-apps.php b/settings/templates/oauth-required-apps.php
new file mode 100644
index 00000000000..d4fce54c59c
--- /dev/null
+++ b/settings/templates/oauth-required-apps.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Copyright (c) 2012, Tom Needham <tom@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+?>
+<div id="oauth-request" class="guest-container">
+ <p><strong><?php echo $_['consumer']['name'].'</strong> '.$_['message']; ?></p>
+ <ul>
+ <?php
+ // Foreach requested scope
+ foreach($_['requiredapps'] as $requiredapp){
+ echo '<li>'.$requiredapp.'</li>';
+ }
+ ?>
+ </ul>
+ <a href="<?php echo OC::$WEBROOT; ?>" id="back-home" class="button">Back to ownCloud</a>
+</div>
diff --git a/settings/templates/oauth.php b/settings/templates/oauth.php
new file mode 100644
index 00000000000..053a8aee6d3
--- /dev/null
+++ b/settings/templates/oauth.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Copyright (c) 2012, Tom Needham <tom@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+?>
+<div id="oauth-request" class="guest-container">
+ <p><strong><?php echo $_['consumer']['name']; ?></strong> is requesting your permission to read, write, modify and delete data from the following apps:</p>
+ <ul>
+ <?php
+ // Foreach requested scope
+ foreach($_['consumer']['scopes'] as $app){
+ echo '<li>'.$app.'</li>';
+ }
+ ?>
+ </ul>
+ <a href="#" class="button">Allow</a>
+ <a href="#" class="button">Disallow</a>
+</div>