aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/api.php11
-rw-r--r--include/oauth.php67
-rw-r--r--library/OAuth1.php13
-rwxr-xr-xutil/shred/FriendicaOAuth.sh173
-rwxr-xr-xutil/shred/JSON.sh129
-rwxr-xr-xutil/shred/OAuth.sh214
-rwxr-xr-xutil/shred/shred211
-rw-r--r--version.inc2
8 files changed, 781 insertions, 39 deletions
diff --git a/include/api.php b/include/api.php
index a49258d18..d76d82626 100644
--- a/include/api.php
+++ b/include/api.php
@@ -1823,9 +1823,13 @@ require_once('include/photos.php');
function api_oauth_request_token(&$a, $type){
try{
$oauth = new FKOAuth1();
- $r = $oauth->fetch_request_token(OAuthRequest::from_request());
+ $req = OAuthRequest::from_request();
+logger('Req: ' . var_export($req,true));
+ $r = $oauth->fetch_request_token($req);
}catch(Exception $e){
- echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage()); killme();
+ logger('oauth_exception: ' . print_r($e->getMessage(),true));
+ echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage());
+ killme();
}
echo $r;
killme();
@@ -1833,7 +1837,8 @@ require_once('include/photos.php');
function api_oauth_access_token(&$a, $type){
try{
$oauth = new FKOAuth1();
- $r = $oauth->fetch_access_token(OAuthRequest::from_request());
+ $req = OAuthRequest::from_request();
+ $r = $oauth->fetch_access_token($req);
}catch(Exception $e){
echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage()); killme();
}
diff --git a/include/oauth.php b/include/oauth.php
index 6ec5285e4..b10802ecd 100644
--- a/include/oauth.php
+++ b/include/oauth.php
@@ -18,11 +18,12 @@ class FKOAuthDataStore extends OAuthDataStore {
function lookup_consumer($consumer_key) {
logger(__function__.":".$consumer_key);
- //echo "<pre>"; var_dump($consumer_key); killme();
-
+// echo "<pre>"; var_dump($consumer_key); killme();
+
$r = q("SELECT client_id, pw, redirect_uri FROM clients WHERE client_id='%s'",
dbesc($consumer_key)
);
+
if (count($r))
return new OAuthConsumer($r[0]['client_id'],$r[0]['pw'],$r[0]['redirect_uri']);
return null;
@@ -30,11 +31,13 @@ class FKOAuthDataStore extends OAuthDataStore {
function lookup_token($consumer, $token_type, $token) {
logger(__function__.":".$consumer.", ". $token_type.", ".$token);
+
$r = q("SELECT id, secret,scope, expires, uid FROM tokens WHERE client_id='%s' AND scope='%s' AND id='%s'",
dbesc($consumer->key),
dbesc($token_type),
dbesc($token)
);
+
if (count($r)){
$ot=new OAuthToken($r[0]['id'],$r[0]['secret']);
$ot->scope=$r[0]['scope'];
@@ -46,12 +49,14 @@ class FKOAuthDataStore extends OAuthDataStore {
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
- //echo __file__.":".__line__."<pre>"; var_dump($consumer,$key); killme();
+// echo __file__.":".__line__."<pre>"; var_dump($consumer,$key); killme();
+
$r = q("SELECT id, secret FROM tokens WHERE client_id='%s' AND id='%s' AND expires=%d",
dbesc($consumer->key),
dbesc($nonce),
intval($timestamp)
);
+
if (count($r))
return new OAuthToken($r[0]['id'],$r[0]['secret']);
return null;
@@ -67,13 +72,14 @@ class FKOAuthDataStore extends OAuthDataStore {
} else {
$k = $consumer;
}
-
+
$r = q("INSERT INTO tokens (id, secret, client_id, scope, expires) VALUES ('%s','%s','%s','%s', UNIX_TIMESTAMP()+%d)",
dbesc($key),
dbesc($sec),
dbesc($k),
'request',
intval(REQUEST_TOKEN_DURATION));
+
if (!$r) return null;
return new OAuthToken($key,$sec);
}
@@ -95,6 +101,7 @@ class FKOAuthDataStore extends OAuthDataStore {
$key = $this->gen_token();
$sec = $this->gen_token();
+
$r = q("INSERT INTO tokens (id, secret, client_id, scope, expires, uid) VALUES ('%s','%s','%s','%s', UNIX_TIMESTAMP()+%d, %d)",
dbesc($key),
dbesc($sec),
@@ -102,6 +109,7 @@ class FKOAuthDataStore extends OAuthDataStore {
'access',
intval(ACCESS_TOKEN_DURATION),
intval($uverifier));
+
if ($r)
$ret = new OAuthToken($key,$sec);
}
@@ -131,9 +139,9 @@ class FKOAuth1 extends OAuthServer {
}
function loginUser($uid){
- logger("FKOAuth1::loginUser $uid");
+ logger("RedOAuth1::loginUser $uid");
$a = get_app();
- $r = q("SELECT * FROM `user` WHERE uid=%d AND `blocked` = 0 AND `account_expired` = 0 AND `verified` = 1 LIMIT 1",
+ $r = q("SELECT * FROM channel WHERE channel_id = %d LIMIT 1",
intval($uid)
);
if(count($r)){
@@ -143,35 +151,36 @@ class FKOAuth1 extends OAuthServer {
header('HTTP/1.0 401 Unauthorized');
die('This api requires login');
}
- $_SESSION['uid'] = $record['uid'];
- $_SESSION['theme'] = $record['theme'];
- $_SESSION['mobile_theme'] = get_pconfig($record['uid'], 'system', 'mobile_theme');
+ $_SESSION['uid'] = $record['channel_id'];
+ $_SESSION['theme'] = $record['channel_theme'];
+ $_SESSION['account_id'] = $record['channel_account_id'];
+ $_SESSION['mobile_theme'] = get_pconfig($record['channel_id'], 'system', 'mobile_theme');
$_SESSION['authenticated'] = 1;
- $_SESSION['page_flags'] = $record['page-flags'];
- $_SESSION['my_url'] = $a->get_baseurl() . '/channel/' . $record['nickname'];
+// $_SESSION['page_flags'] = $record['page-flags'];
+ $_SESSION['my_url'] = $a->get_baseurl() . '/channel/' . $record['channel_address'];
$_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
+ $_SESSION['allow_api'] = true;
- //notice( t("Welcome back ") . $record['username'] . EOL);
- $a->user = $record;
+ $a->channel = $record;
- if(strlen($a->user['timezone'])) {
- date_default_timezone_set($a->user['timezone']);
- $a->timezone = $a->user['timezone'];
+ if(strlen($a->channel['channel_timezone'])) {
+ date_default_timezone_set($a->channel['channel_timezone']);
+// $a->timezone = $a->user['timezone'];
}
- $r = q("SELECT * FROM `contact` WHERE `uid` = %s AND `self` = 1 LIMIT 1",
- intval($_SESSION['uid']));
- if(count($r)) {
- $a->contact = $r[0];
- $a->cid = $r[0]['id'];
- $_SESSION['cid'] = $a->cid;
- }
- q("UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d LIMIT 1",
- dbesc(datetime_convert()),
- intval($_SESSION['uid'])
- );
-
- call_hooks('logged_in', $a->user);
+// $r = q("SELECT * FROM `contact` WHERE `uid` = %s AND `self` = 1 LIMIT 1",
+// intval($_SESSION['uid']));
+// if(count($r)) {
+// $a->contact = $r[0];
+// $a->cid = $r[0]['id'];
+// $_SESSION['cid'] = $a->cid;
+// }
+// q("UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d LIMIT 1",
+// dbesc(datetime_convert()),
+// intval($_SESSION['uid'])
+// );
+//
+// call_hooks('logged_in', $a->user);
}
}
diff --git a/library/OAuth1.php b/library/OAuth1.php
index 0db6fabcb..b790655af 100644
--- a/library/OAuth1.php
+++ b/library/OAuth1.php
@@ -273,6 +273,7 @@ class OAuthRequest {
&& @strstr($request_headers["Content-Type"],
"application/x-www-form-urlencoded")
) {
+
$post_data = OAuthUtil::parse_parameters(
file_get_contents(self::$POST_INPUT)
);
@@ -286,15 +287,15 @@ class OAuthRequest {
$request_headers['Authorization']
);
$parameters = array_merge($parameters, $header_parameters);
+
}
}
// fix for friendica redirect system
-
+ // FIXME or don't, but figure out if this is absolutely necessary and act accordingly
$http_url = substr($http_url, 0, strpos($http_url,$parameters['q'])+strlen($parameters['q']));
unset( $parameters['q'] );
- //echo "<pre>".__function__."\n"; var_dump($http_method, $http_url, $parameters, $_SERVER['REQUEST_URI']); killme();
return new OAuthRequest($http_method, $http_url, $parameters);
}
@@ -514,9 +515,7 @@ class OAuthServer {
*/
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;
@@ -525,7 +524,6 @@ class OAuthServer {
// Rev A change
$callback = $request->get_parameter('oauth_callback');
$new_token = $this->data_store->new_request_token($consumer, $callback);
-
return $new_token;
}
@@ -796,7 +794,8 @@ class OAuthUtil {
);
$out[$key] = $value;
}
- } else {
+ }
+ if((! isset($out)) || (! array_key_exists('Authorization',$out))) {
// otherwise we don't have apache and are just going to have to hope
// that $_SERVER actually contains what we need
$out = array();
@@ -806,6 +805,8 @@ class OAuthUtil {
$out['Content-Type'] = $_ENV['CONTENT_TYPE'];
foreach ($_SERVER as $key => $value) {
+ if($key === 'REDIRECT_REMOTE_USER')
+ $out['Authorization'] = $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
diff --git a/util/shred/FriendicaOAuth.sh b/util/shred/FriendicaOAuth.sh
new file mode 100755
index 000000000..a20da7879
--- /dev/null
+++ b/util/shred/FriendicaOAuth.sh
@@ -0,0 +1,173 @@
+#!/bin/bash
+# Copyright (c) 2012 Fabio Comuni
+# Copyright (c) 2012 Michael Nowack
+# Copyright (c) 2010, 2012 Yu-Jie Lin
+#
+# 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.
+
+FRIENDICAOAUTH_VERSION=0.1.1
+
+F_API_VERSION="1"
+
+# Friendica API endpoints
+
+F_ACCOUNF_UPDATE_PROFILE_IMAGE="${redmatrix_url}/api/account/update_profile_image"
+F_STATUSES_UPDATE="${redmatrix_url}/api/statuses/update"
+F_STATUSES_HOME_TIMELINE="${redmatrix_url}/api/statuses/home_timeline"
+
+F_REQUESF_TOKEN=${redmatrix_url}'/api/oauth/request_token'
+F_ACCESS_TOKEN=${redmatrix_url}'/api/oauth/access_token'
+F_AUTHORIZE_TOKEN=${redmatrix_url}'/api/oauth/authorize'
+
+# Source OAuth.sh
+
+OAuth_sh=$(which OAuth.sh)
+(( $? != 0 )) && echo 'Unable to locate OAuth.sh! Make sure it is in searching PATH.' && exit 1
+source "$OAuth_sh"
+
+FO_debug () {
+ # Print out all parameters, each in own line
+ [[ "$FO_DEBUG" == "" ]] && return
+ local t=$(date +%FT%T.%N)
+ while (( $# > 0 )); do
+ echo "[FO][DEBUG][$t] $1"
+ shift 1
+ done
+ }
+
+FO_extract_value () {
+ # $1 key name
+ # $2 string to find
+ egrep -o "$1=[a-zA-Z0-9-]*" <<< "$2" | cut -d\= -f 2
+ }
+
+
+FO_init() {
+ # Initialize FriendicaOAuth
+ oauth_version='1.0'
+ oauth_signature_method='HMAC-SHA1'
+ oauth_basic_params=(
+ $(OAuth_param 'oauth_consumer_key' "$oauth_consumer_key")
+ $(OAuth_param 'oauth_signature_method' "$oauth_signature_method")
+ $(OAuth_param 'oauth_version' "$oauth_version")
+ )
+ }
+
+FO_access_token_helper () {
+ # Help guide user to get access token
+
+ local resp PIN
+
+ # Request Token
+
+ local auth_header="$(_OAuth_authorization_header 'Authorization' "$redmatrix_url/" "$oauth_consumer_key" "$oauth_consumer_secret" '' '' "$oauth_signature_method" "$oauth_version" "$(OAuth_nonce)" "$(OAuth_timestamp)" 'POST' "$F_REQUESF_TOKEN" "$(OAuth_param 'oauth_callback' 'oob')"), $(OAuth_param_quote 'oauth_callback' 'oob')"
+
+# echo $auth_header
+# echo $F_REQUESF_TOKEN
+
+ resp=$(curl -s -d '' -H "$auth_header" "$F_REQUESF_TOKEN")
+ FO_rval=$?
+ (( $? != 0 )) && return $FO_rval
+
+ local _oauth_token=$(FO_extract_value 'oauth_token' "$resp")
+ local _oauth_token_secret=$(FO_extract_value 'oauth_token_secret' "$resp")
+
+ echo 'Please go to the following link to get the PIN:'
+ echo " ${F_AUTHORIZE_TOKEN}?oauth_token=$_oauth_token"
+
+ read -p 'PIN: ' PIN
+
+ # Access Token
+
+ local auth_header="$(_OAuth_authorization_header 'Authorization' "$redmatrix_url/" "$oauth_consumer_key" "$oauth_consumer_secret" "$_oauth_token" "$_oauth_token_secret" "$oauth_signature_method" "$oauth_version" "$(OAuth_nonce)" "$(OAuth_timestamp)" 'POST' "$F_ACCESS_TOKEN" "$(OAuth_param 'oauth_verifier' "$PIN")"), $(OAuth_param_quote 'oauth_verifier' "$PIN")"
+
+ resp=$(curl -s -d "" -H "$auth_header" "$F_ACCESS_TOKEN")
+ FO_rval=$?
+ (( $? != 0 )) && return $FO_rval
+
+ FO_ret=(
+ $(FO_extract_value 'oauth_token' "$resp")
+ $(FO_extract_value 'oauth_token_secret' "$resp")
+ $(FO_extract_value 'user_id' "$resp")
+ $(FO_extract_value 'screen_name' "$resp")
+ )
+ }
+
+# APIs
+######
+
+FO_statuses_update () {
+ # $1 format
+ # $2 status
+ # $3 in_reply_to_status_id
+ # The followins are not implemented yet:
+ # $4 lat
+ # $5 long
+ # $6 place_id
+ # $7 display_coordinates
+ local format="$1"
+ [[ "$format" == "" ]] && format="xml"
+
+ local params=(
+ $(OAuth_param 'status' "$2")
+ )
+
+ params[${#params[@]}]=$(OAuth_param 'source' "fcli")
+
+ [[ "$3" != "" ]] && params[${#params[@]}]=$(OAuth_param 'in_reply_to_status_id' "$3") && local in_reply_to_status_id=( '--data-urlencode' "in_reply_to_status_id=$3" )
+
+
+ local auth_header=$(OAuth_authorization_header 'Authorization' "$redmatrix_url" '' '' 'POST' "$F_STATUSES_UPDATE.$format" ${params[@]})
+
+
+ FO_ret=$(curl -s -H "$auth_header" --data-urlencode "status=$2" --data-urlencode "source=fcli" ${in_reply_to_status_id[@]} "$F_STATUSES_UPDATE.$format")
+
+ FO_rval=$?
+ return $FO_rval
+ }
+
+
+# gets the user home_timeline.
+#
+# @sets FO_ret API response
+# @returns status
+# @public
+FO_statuses_home_timeline () {
+ # $1 format
+ # $2 screen_name
+ # $3 count
+ local format="$1"
+ local screen_name="$2"
+ local count="$3"
+ [[ "$format" == "" ]] && format="xml"
+ [[ "$count" == "" ]] && count=1
+
+ local params=(
+ $(OAuth_param 'screen_name' $screen_name)
+ $(OAuth_param 'count' $count)
+ )
+g
+ local auth_header=$(OAuth_authorization_header 'Authorization' "$redmatrix_url" '' '' 'GET' "$F_STATUSES_HOME_TIMELINE.$format" ${params[@]})
+
+ convscreen=$(OAuth_PE "$screen_name");
+ FO_ret=$(curl -s --get "${F_STATUSES_HOME_TIMELINE}.${format}" --data "screen_name=${convscreen}&count=${count}" --header "${auth_header}")
+ FO_rval=$?
+
+ return $FO_rval
+ }
diff --git a/util/shred/JSON.sh b/util/shred/JSON.sh
new file mode 100755
index 000000000..65f5f1f66
--- /dev/null
+++ b/util/shred/JSON.sh
@@ -0,0 +1,129 @@
+# The MIT License
+#
+# Copyright (c) 2011 Dominic Tarr
+#
+# 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.
+#
+#
+# https://github.com/dominictarr/JSON.sh
+#
+throw () {
+ echo "$*" >&2
+ exit 1
+}
+
+tokenize () {
+ local ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
+ local CHAR='[^[:cntrl:]"\\]'
+ local STRING="\"$CHAR*($ESCAPE$CHAR*)*\""
+ local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?'
+ local KEYWORD='null|false|true'
+ local SPACE='[[:space:]]+'
+ egrep -ao "$STRING|$NUMBER|$KEYWORD|$SPACE|." --color=never |
+ egrep -v "^$SPACE$" # eat whitespace
+}
+
+parse_array () {
+ local index=0
+ local ary=''
+ read -r token
+ case "$token" in
+ ']') ;;
+ *)
+ while :
+ do
+ parse_value "$1" "$index"
+ let index=$index+1
+ ary="$ary""$value"
+ read -r token
+ case "$token" in
+ ']') break ;;
+ ',') ary="$ary," ;;
+ *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;;
+ esac
+ read -r token
+ done
+ ;;
+ esac
+ value=`printf '[%s]' "$ary"`
+}
+
+parse_object () {
+ local key
+ local obj=''
+ read -r token
+ case "$token" in
+ '}') ;;
+ *)
+ while :
+ do
+ case "$token" in
+ '"'*'"') key=$token ;;
+ *) throw "EXPECTED string GOT ${token:-EOF}" ;;
+ esac
+ read -r token
+ case "$token" in
+ ':') ;;
+ *) throw "EXPECTED : GOT ${token:-EOF}" ;;
+ esac
+ read -r token
+ parse_value "$1" "$key"
+ obj="$obj$key:$value"
+ read -r token
+ case "$token" in
+ '}') break ;;
+ ',') obj="$obj," ;;
+ *) throw "EXPECTED , or } GOT ${token:-EOF}" ;;
+ esac
+ read -r token
+ done
+ ;;
+ esac
+ value=`printf '{%s}' "$obj"`
+}
+
+parse_value () {
+ local jpath="${1:+$1,}$2"
+ case "$token" in
+ '{') parse_object "$jpath" ;;
+ '[') parse_array "$jpath" ;;
+ # At this point, the only valid single-character tokens are digits.
+ ''|[^0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;;
+ *) value=$token ;;
+ esac
+ printf "[%s]\t%s\n" "$jpath" "$value"
+}
+
+parse () {
+ read -r token
+ parse_value
+ read -r token
+ case "$token" in
+ '') ;;
+ *) throw "EXPECTED EOF GOT $token" ;;
+ esac
+}
+
+if [ $0 = $BASH_SOURCE ];
+then
+ tokenize | parse
+fi
diff --git a/util/shred/OAuth.sh b/util/shred/OAuth.sh
new file mode 100755
index 000000000..4be4ed35b
--- /dev/null
+++ b/util/shred/OAuth.sh
@@ -0,0 +1,214 @@
+#!/bin/bash
+# Copyright (c) 2010, 2012 Yu-Jie Lin
+#
+# 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.
+
+BASHOAUTH_VERSION=0.1.2
+
+OAuth_debug () {
+ # Print out all parameters, each in own line
+ [[ "$OAUTH_DEBUG" == "" ]] && return
+ local t=$(date +%FT%T.%N)
+ while (( $# > 0 )); do
+ echo "[OAuth][DEBUG][$t] $1"
+ shift 1
+ done
+ }
+
+OAuth_nonce () {
+ # Return a nonce
+ md5sum <<< "$RANDOM-$(date +%s.%N)" | cut -d' ' -f 1
+ }
+
+OAuth_timestamp () {
+ # Return timestamp
+ echo "$(date +%s)"
+ }
+
+OAuth_PE () {
+ # Encode $1 using Percent-encoding as defined in
+ # http://tools.ietf.org/html/rfc5849#section-3.6
+ # Any character other than [a-zA-Z0-9-._~] is converted into format %XX
+ [ -n "$1" ] \
+ && echo -n "$1" | perl -p -e 's/([^A-Za-z0-9-._~])/sprintf("%%%02X", ord($1))/seg'
+}
+
+OAuth_PE_file () {
+ # Encode a file $1 using Percent-encoding as defined in
+ # http://tools.ietf.org/html/rfc5849#section-3.6
+ # $1 a filename, not the content of file
+ perl -p -e 's/([^A-Za-z0-9-._~])/sprintf("%%%02X", ord($1))/seg' < "$1"
+}
+
+OAuth_params_string () {
+ # Sort the paramters and join them into one-line string
+ while (( $# > 0 )); do
+ echo $1
+ shift 1
+ done | sort | tr '\n' '&' | sed 's/&$//'
+ }
+
+OAuth_base_string () {
+ # $1 method: "GET", "POST", etc
+ # $2 url
+ # $3-$N params
+ local method=$1
+ local url=$2
+ shift 2
+
+ local params_string=$(OAuth_params_string $@)
+
+ echo "$method&$(OAuth_PE "$url")&$(OAuth_PE "$params_string")"
+ }
+
+OAuth_param () {
+ # Return a percent encoded key-value pair
+ # $1 key
+ # $2 value
+ echo "$(OAuth_PE "$1")=$(OAuth_PE "$2")"
+ }
+
+OAuth_param_quote () {
+ # Return a percent encoded key-value pair, value is quoted
+ # $1 key
+ # $2 value
+ echo "$(OAuth_PE "$1")=\"$(OAuth_PE "$2")\""
+ }
+
+OAuth_param_file () {
+ # Return a percent encoded key-value pair, the value is an encoded file content
+ # $1 key
+ # $2 filename
+ echo "$(OAuth_PE "$1")=$(OAuth_PE_file "$2")"
+ }
+
+OAuth_param_raw_value () {
+ # Return a percent encoded key-value pair, only key will be encoded by this function
+ # $1 key
+ # $2 value
+ echo "$(OAuth_PE "$1")=$2"
+ }
+
+OAuth_HMAC_SHA1 () {
+ # Hash the text $1 with key $2
+ local text="$1"
+ local key="$2"
+ echo -n "$text" | openssl dgst -sha1 -binary -hmac "$key" | base64
+ }
+
+_OAuth_signature () {
+ # Return the signature, note it's necessary to pass to OAuth_PE before add to header
+ # $1 signature_method
+ # $2 base_string
+ # $3 consumer_secret
+ # $4 token_secret
+ local signature_method="OAuth_${1//-/_}"
+ local base_string=$2
+ local c_secret=$3
+ local t_secret=$4
+ $signature_method "$base_string" "$c_secret&$t_secret"
+ }
+
+OAuth_signature () {
+ # Return the signature, note it's necessary to pass to OAuth_PE before add to header
+ # $1 base_string
+ _OAuth_signature "$oauth_signature_method" "$1" "$oauth_consumer_secret" "$oauth_token_secret"
+ }
+
+_OAuth_authorization_header_params_string () {
+ while (( $# > 0 )); do
+ echo -n "$(cut -d\= -f 1 <<< "$1")=\"$(cut -d\= -f 2 <<< "$1")\""
+ shift 1
+ # Use break to prevent error code being returned
+ (( $# > 0 )) && echo -n ', ' || break
+ done
+ }
+
+_OAuth_authorization_header () {
+ # Return header string
+ # $1 header key
+ # $2 OAuth realm, can be empty string
+ # $3 OAuth consumer key
+ # $4 OAuth consumer secret
+ # $5 OAuth token
+ # $6 OAuth token secret
+ # $7 OAuth signature method
+ # $8 OAuth version
+ # $9 nonce
+ # $10 timestamp
+ # $11 method
+ # $12 url
+ # $13-$N params
+ echo -n "$1: OAuth "
+ [[ "$2" != "" ]] && echo -n "realm=\"$2\", "
+ local oauth_consumer_key="$3"
+ local oauth_consumer_secret="$4"
+ local oauth_token="$5"
+ local oauth_token_secret="$6"
+ local oauth_signature_method="$7"
+ local oauth_version="$8"
+ local oauth_nonce="$9"
+ [[ "$oauth_nonce" == "" ]] && oauth_nonce="$(OAuth_nonce)"
+ local oauth_timestamp="${10}"
+ [[ "$oauth_timestamp" == "" ]] && oauth_timestamp="$(OAuth_timestamp)"
+ local method="${11}"
+ local url="${12}"
+ shift 12
+ local params=(
+ $(OAuth_param 'oauth_consumer_key' "$oauth_consumer_key")
+ $(OAuth_param 'oauth_signature_method' "$oauth_signature_method")
+ $(OAuth_param 'oauth_version' "$oauth_version")
+ $(OAuth_param 'oauth_nonce' "$oauth_nonce")
+ $(OAuth_param 'oauth_timestamp' "$oauth_timestamp")
+ )
+ [[ "$oauth_token" != "" ]] && params[${#params[@]}]=$(OAuth_param 'oauth_token' "$oauth_token")
+ local sign_params=${params[@]}
+ while (( $# > 0 )); do
+ sign_params[${#sign_params[@]}]="$1"
+ shift 1
+ done
+ local base_string=$(OAuth_base_string "$method" "$url" ${sign_params[@]})
+ local signature=$(_OAuth_signature "$oauth_signature_method" "$base_string" "$oauth_consumer_secret" "$oauth_token_secret")
+ params[${#params[@]}]=$(OAuth_param 'oauth_signature' "$signature")
+ _OAuth_authorization_header_params_string ${params[@]}
+ }
+
+OAuth_authorization_header () {
+ # Return header string
+ # $1 header key
+ # $2 OAuth realm, can be empty string
+ # $3 OAuth nonce
+ # $4 OAuth timestamp
+ # $5 method
+ # $6 url
+ # $7-$N params
+ local header_key="$1"
+ local realm="$2"
+ local oauth_nonce="$3"
+ local oauth_timestamp="$4"
+ local method="$5"
+ local url="$6"
+ shift 6
+ local params=()
+ while (( $# > 0 )); do
+ params[${#params[@]}]="$1"
+ shift 1
+ done
+ _OAuth_authorization_header "$header_key" "$realm" "$oauth_consumer_key" "$oauth_consumer_secret" "$oauth_token" "$oauth_token_secret" "$oauth_signature_method" "$oauth_version" "$oauth_nonce" "$oauth_timestamp" "$method" "$url" ${params[@]}
+ }
diff --git a/util/shred/shred b/util/shred/shred
new file mode 100755
index 000000000..113898ff9
--- /dev/null
+++ b/util/shred/shred
@@ -0,0 +1,211 @@
+#!/bin/bash
+# Copyright (c) 2012 Fabio Comuni
+# Copyright (c) 2010, 2012 Yu-Jie Lin
+#
+# 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.
+
+FCLI_RC="$HOME/.shred.rc"
+
+# Source Config
+[[ -f "$FCLI_RC" ]] && . "$FCLI_RC" || show_config_help 1
+
+# Source FriendicaOAuth.sh
+OAuth_sh=$(which FriendicaOAuth.sh)
+(( $? != 0 )) && echo 'Unable to locate FriendicaOAuth.sh! Make sure it is in searching PATH.' && exit 1
+source "$OAuth_sh"
+
+# Source JSON.sh
+JSON_sh=$(which JSON.sh)
+(( $? != 0 )) && echo 'Unable to locate JSON.sh! Make sure it is in searching PATH.' && exit 1
+source "$JSON_sh"
+
+
+usage () {
+ echo "usage: $0 options
+
+OPTIONS:
+ -h Show this message
+
+ -c Command
+
+ Valid Commands:
+ statuses_update
+ home_timeline
+
+Use -h -c command to get options for the command.
+"
+ exit $1
+ }
+
+show_config_help () {
+ echo "Please create $FCLI_RC with:
+redmatrix_url=YOR_SERVER_URL (no trailing /)
+oauth_consumer_key=YOUR_CONSUMER_KEY
+oauth_consumer_secret=YOUR_CONSUMER_SECRET
+
+You can register new app consumer key and secret at
+ http://yourserver.com/settings/oauth
+"
+ exit $1
+ }
+
+
+show_statuses_update () {
+ echo "Command statuses_update
+
+Requires:
+ -s status
+
+Optional:
+ -r in_reply_to_status_id
+"
+ exit $1
+ }
+
+show_home_timeline () {
+ echo "Command home_timeline"
+
+ exit $1
+ }
+
+#json helper
+#
+# usage:
+# echo "$parsed_json" | js key1 [key2 [key3 ...]][,]
+#
+# echoes the value of json[key1][key2][key3], without surronding quotes
+# with "," as last argument, no newline is printed
+#
+js () {
+ local arg
+ local rg='^\['
+ local ret
+ for arg in $@
+ do
+ [[ "$arg" == "," ]] && break;
+ if [[ $arg == ${arg//[0-9]/} ]]
+ then
+ rg="${rg}\"$arg\","
+ else
+ rg="${rg}$arg,"
+ fi
+ done
+ rg="${rg%?}\]"
+ ret=$(grep $rg | cut -f 2 | sed 's/^"\(.*\)"$/\1/' | sed "s/\\\\\//\//g" )
+ if [[ "$arg" == "," ]]
+ then
+ echo -e "$ret" | tr -d '\012\015'
+ else
+ echo -e "$ret"
+ fi
+}
+
+
+load_config () {
+
+ [[ "$oauth_consumer_key" == "" ]] && show_config_help 1
+ [[ "$oauth_consumer_secret" == "" ]] && show_config_help 1
+
+
+ FO_init
+
+ if [[ "$oauth_token" == "" ]] || [[ "$oauth_token_secret" == "" ]]; then
+ FO_access_token_helper
+ if (( $? == 0 )); then
+ oauth_token=${FO_ret[0]}
+ oauth_token_secret=${FO_ret[1]}
+ echo "oauth_token='${FO_ret[0]}'" >> "$FCLI_RC"
+ echo "oauth_token_secret='${FO_ret[1]}'" >> "$FCLI_RC"
+ echo "Token saved."
+ else
+ echo 'Unable to get access token'
+ exit 1
+ fi
+ fi
+ }
+
+main () {
+ load_config
+
+ fcli_command=
+ fcli_status=
+ fcli_in_reply_to_status_id=
+ fcli_file=
+ fcli_help_flag=
+ while getopts "c:s:r:f:h" name
+ do
+ case $name in
+ c) fcli_command="$OPTARG";;
+ s) fcli_status="$OPTARG";;
+ r) fcli_in_reply_to_status_id="$OPTARG";;
+ f) fcli_file="$OPTARG";;
+ h) fcli_help_flag="1";;
+ ?) usage
+ exit 2;;
+ esac
+ done
+
+ if [[ "$fcli_help_flag" == "1" ]]; then case $fcli_command in
+ statuses_update)
+ show_statuses_update 0
+ ;;
+ home_timeline)
+ show_home_timeline 0
+ ;;
+ *)
+ [[ "$fcli_command" == "" ]] && usage 0
+ usage 1
+ esac ; fi
+
+ case $fcli_command in
+ home_timeline)
+ FO_statuses_home_timeline 'json' '' 5
+ JS_Parsed=$(echo "$FO_ret" | tokenize | parse)
+ for id in 0 1 2 3 4
+ do
+ echo "$JS_Parsed" | js $id "user" "name" ,
+ echo -n " - "
+ echo "$JS_Parsed" | js $id "created_at"
+ echo "$JS_Parsed" | js $id "text"
+ echo ""
+ echo "------------------------------------------------------------------------------"
+ done
+
+ return $FO_rval
+ ;;
+ statuses_update)
+ [[ "$fcli_status" == "" ]] && show_statuses_update 1
+ FO_statuses_update 'json' "$fcli_status" "$fcli_in_reply_to_status_id"
+ JS_Parsed=$(echo "$FO_ret" | tokenize | parse)
+ echo "$JS_Parsed" | js "user" "name" ,
+ echo -n " - "
+ echo "$JS_Parsed" | js "created_at"
+ echo "$JS_Parsed" | js "text"
+ echo ""
+ echo "------------------------------------------------------------------------------"
+ return $FO_rval
+ ;;
+ *)
+ usage 1
+ ;;
+ esac
+ return 0
+ }
+
+main "$@"
diff --git a/version.inc b/version.inc
index 2ee9add97..186ac999c 100644
--- a/version.inc
+++ b/version.inc
@@ -1 +1 @@
-2013-09-15.437
+2013-09-16.438