2010-07-01 23:48:07 +00:00
< ? php
2017-03-12 00:11:35 +00:00
/**
* @ brief Calculate the hash that is needed for the " Friendica " cookie
*
* @ param array $user Record from " user " table
*
* @ return string Hashed data
*/
function cookie_hash ( $user ) {
return ( hash ( " sha256 " , get_config ( " system " , " site_prvkey " ) .
$user [ " uprvkey " ] .
$user [ " password " ]));
}
/**
* @ brief Set the " Friendica " cookie
*
* @ param int $time
* @ param array $user Record from " user " table
*/
function new_cookie ( $time , $user = array ()) {
2017-03-13 22:09:09 +00:00
if ( $time != 0 ) {
2017-03-12 00:11:35 +00:00
$time = $time + time ();
2017-03-13 22:09:09 +00:00
}
2017-03-12 00:11:35 +00:00
2017-03-13 22:09:09 +00:00
if ( $user ) {
2017-03-12 00:11:35 +00:00
$value = json_encode ( array ( " uid " => $user [ " uid " ],
" hash " => cookie_hash ( $user ),
" ip " => $_SERVER [ 'REMOTE_ADDR' ]));
2017-03-13 22:09:09 +00:00
}
else {
2017-03-12 00:11:35 +00:00
$value = " " ;
2017-03-13 22:09:09 +00:00
}
2017-03-12 00:11:35 +00:00
setcookie ( " Friendica " , $value , $time , " / " , " " ,
( get_config ( 'system' , 'ssl_policy' ) == SSL_POLICY_FULL ), true );
}
2012-11-09 00:00:37 +00:00
function authenticate_success ( $user_record , $login_initial = false , $interactive = false , $login_refresh = false ) {
2012-01-12 23:46:39 +00:00
$a = get_app ();
$_SESSION [ 'uid' ] = $user_record [ 'uid' ];
$_SESSION [ 'theme' ] = $user_record [ 'theme' ];
2012-09-06 23:24:34 +00:00
$_SESSION [ 'mobile-theme' ] = get_pconfig ( $user_record [ 'uid' ], 'system' , 'mobile_theme' );
2012-01-12 23:46:39 +00:00
$_SESSION [ 'authenticated' ] = 1 ;
$_SESSION [ 'page_flags' ] = $user_record [ 'page-flags' ];
2016-12-19 13:26:13 +00:00
$_SESSION [ 'my_url' ] = App :: get_baseurl () . '/profile/' . $user_record [ 'nickname' ];
$_SESSION [ 'my_address' ] = $user_record [ 'nickname' ] . '@' . substr ( App :: get_baseurl (), strpos ( App :: get_baseurl (), '://' ) + 3 );
2012-01-12 23:46:39 +00:00
$_SESSION [ 'addr' ] = $_SERVER [ 'REMOTE_ADDR' ];
$a -> user = $user_record ;
if ( $interactive ) {
2017-02-27 23:37:15 +00:00
if ( $a -> user [ 'login_date' ] <= NULL_DATE ) {
2012-01-12 23:46:39 +00:00
$_SESSION [ 'return_url' ] = 'profile_photo/new' ;
$a -> module = 'profile_photo' ;
info ( t ( " Welcome " ) . $a -> user [ 'username' ] . EOL );
info ( t ( 'Please upload a profile photo.' ) . EOL );
}
else
info ( t ( " Welcome back " ) . $a -> user [ 'username' ] . EOL );
}
$member_since = strtotime ( $a -> user [ 'register_date' ]);
if ( time () < ( $member_since + ( 60 * 60 * 24 * 14 )))
$_SESSION [ 'new_member' ] = true ;
else
$_SESSION [ 'new_member' ] = false ;
if ( strlen ( $a -> user [ 'timezone' ])) {
date_default_timezone_set ( $a -> user [ 'timezone' ]);
$a -> timezone = $a -> user [ 'timezone' ];
}
2014-03-11 22:52:32 +00:00
$master_record = $a -> user ;
2012-01-27 20:56:36 +00:00
2012-01-27 00:52:12 +00:00
if (( x ( $_SESSION , 'submanage' )) && intval ( $_SESSION [ 'submanage' ])) {
$r = q ( " select * from user where uid = %d limit 1 " ,
intval ( $_SESSION [ 'submanage' ])
);
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r ))
2012-01-27 00:52:12 +00:00
$master_record = $r [ 0 ];
}
2013-03-19 00:31:21 +00:00
$r = q ( " SELECT `uid`,`username`,`nickname` FROM `user` WHERE `password` = '%s' AND `email` = '%s' AND `account_removed` = 0 " ,
2012-01-27 00:52:12 +00:00
dbesc ( $master_record [ 'password' ]),
dbesc ( $master_record [ 'email' ])
2012-01-12 23:46:39 +00:00
);
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r ))
2012-01-12 23:46:39 +00:00
$a -> identities = $r ;
2012-01-27 00:52:12 +00:00
else
$a -> identities = array ();
2012-01-12 23:46:39 +00:00
2015-05-09 21:47:45 +00:00
$r = q ( " select `user`.`uid`, `user`.`username`, `user`.`nickname`
2014-03-09 08:19:14 +00:00
from manage INNER JOIN user on manage . mid = user . uid where `user` . `account_removed` = 0
2013-03-19 00:31:21 +00:00
and `manage` . `uid` = % d " ,
2012-01-27 00:52:12 +00:00
intval ( $master_record [ 'uid' ])
);
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r ))
2012-01-27 00:52:12 +00:00
$a -> identities = array_merge ( $a -> identities , $r );
2012-01-12 23:46:39 +00:00
2012-01-27 20:56:36 +00:00
if ( $login_initial )
logger ( 'auth_identities: ' . print_r ( $a -> identities , true ), LOGGER_DEBUG );
2012-11-09 00:00:37 +00:00
if ( $login_refresh )
logger ( 'auth_identities refresh: ' . print_r ( $a -> identities , true ), LOGGER_DEBUG );
2012-01-27 20:56:36 +00:00
2012-01-12 23:46:39 +00:00
$r = q ( " SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1 " ,
intval ( $_SESSION [ 'uid' ]));
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r )) {
2012-01-12 23:46:39 +00:00
$a -> contact = $r [ 0 ];
$a -> cid = $r [ 0 ][ 'id' ];
$_SESSION [ 'cid' ] = $a -> cid ;
}
header ( 'X-Account-Management-Status: active; name="' . $a -> user [ 'username' ] . '"; id="' . $a -> user [ 'nickname' ] . '"' );
2012-11-09 00:00:37 +00:00
if ( $login_initial || $login_refresh ) {
2012-01-12 23:46:39 +00:00
2016-10-01 13:57:37 +00:00
q ( " UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d " ,
2012-01-12 23:46:39 +00:00
dbesc ( datetime_convert ()),
intval ( $_SESSION [ 'uid' ])
);
2015-05-09 21:47:45 +00:00
// Set the login date for all identities of the user
q ( " UPDATE `user` SET `login_date` = '%s' WHERE `password` = '%s' AND `email` = '%s' AND `account_removed` = 0 " ,
dbesc ( datetime_convert ()),
dbesc ( $master_record [ 'password' ]),
dbesc ( $master_record [ 'email' ])
);
2012-11-09 00:00:37 +00:00
}
2017-03-12 00:11:35 +00:00
if ( $login_initial ) {
// If the user specified to remember the authentication, then set a cookie
// that expires after one week (the default is when the browser is closed).
// The cookie will be renewed automatically.
// The week ensures that sessions will expire after some inactivity.
if ( $_SESSION [ 'remember' ]) {
logger ( 'Injecting cookie for remembered user ' . $_SESSION [ 'remember_user' ][ 'nickname' ]);
new_cookie ( 604800 , $user_record );
unset ( $_SESSION [ 'remember' ]);
}
}
2016-12-20 16:43:46 +00:00
if ( $login_initial ) {
2012-01-12 23:46:39 +00:00
call_hooks ( 'logged_in' , $a -> user );
2016-12-20 16:43:46 +00:00
if (( $a -> module !== 'home' ) && isset ( $_SESSION [ 'return_url' ])) {
2016-12-19 13:26:13 +00:00
goaway ( App :: get_baseurl () . '/' . $_SESSION [ 'return_url' ]);
2016-12-20 16:43:46 +00:00
}
2012-01-12 23:46:39 +00:00
}
}
2017-01-09 12:09:01 +00:00
function can_write_wall ( App $a , $owner ) {
2010-10-18 03:24:58 +00:00
2010-12-03 05:09:55 +00:00
static $verified = 0 ;
2010-10-18 03:24:58 +00:00
2016-12-20 16:43:46 +00:00
if (( ! ( local_user ())) && ( ! ( remote_user ()))) {
2010-12-03 05:09:55 +00:00
return false ;
2016-12-20 16:43:46 +00:00
}
2010-12-03 05:09:55 +00:00
$uid = local_user ();
2016-12-20 16:43:46 +00:00
if (( $uid ) && ( $uid == $owner )) {
2010-12-03 05:09:55 +00:00
return true ;
}
2016-12-20 16:43:46 +00:00
if ( remote_user ()) {
2010-07-01 23:48:07 +00:00
2012-03-05 23:04:43 +00:00
// use remembered decision and avoid a DB lookup for each and every display item
2010-12-03 05:09:55 +00:00
// DO NOT use this function if there are going to be multiple owners
2012-03-05 23:04:43 +00:00
// We have a contact-id for an authenticated remote user, this block determines if the contact
// belongs to this page owner, and has the necessary permissions to post content
2016-12-20 16:43:46 +00:00
if ( $verified === 2 ) {
2010-12-03 05:09:55 +00:00
return true ;
2016-12-20 16:43:46 +00:00
} elseif ( $verified === 1 ) {
2010-12-03 05:09:55 +00:00
return false ;
2016-12-20 16:43:46 +00:00
} else {
2012-09-05 05:50:28 +00:00
$cid = 0 ;
2016-12-20 16:43:46 +00:00
if ( is_array ( $_SESSION [ 'remote' ])) {
foreach ( $_SESSION [ 'remote' ] as $visitor ) {
if ( $visitor [ 'uid' ] == $owner ) {
2012-09-05 05:50:28 +00:00
$cid = $visitor [ 'cid' ];
break ;
}
}
}
2016-12-20 16:43:46 +00:00
if ( ! $cid ) {
2012-09-05 05:50:28 +00:00
return false ;
2016-12-20 16:43:46 +00:00
}
2012-03-05 23:04:43 +00:00
2017-01-09 12:09:01 +00:00
$r = q ( " SELECT `contact`.*, `user`.`page-flags` FROM `contact` INNER JOIN `user` on `user`.`uid` = `contact`.`uid`
WHERE `contact` . `uid` = % d AND `contact` . `id` = % d AND `contact` . `blocked` = 0 AND `contact` . `pending` = 0
2011-03-21 00:54:50 +00:00
AND `user` . `blockwall` = 0 AND `readonly` = 0 AND ( `contact` . `rel` IN ( % d , % d ) OR `user` . `page-flags` = % d ) LIMIT 1 " ,
2010-11-09 04:43:58 +00:00
intval ( $owner ),
2012-09-05 05:50:28 +00:00
intval ( $cid ),
2011-08-18 23:47:45 +00:00
intval ( CONTACT_IS_SHARING ),
2011-08-07 23:15:54 +00:00
intval ( CONTACT_IS_FRIEND ),
2010-11-09 04:43:58 +00:00
intval ( PAGE_COMMUNITY )
);
2012-03-05 23:04:43 +00:00
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r )) {
2010-12-03 05:09:55 +00:00
$verified = 2 ;
return true ;
}
else {
$verified = 1 ;
}
2010-11-09 04:43:58 +00:00
}
2010-12-03 05:09:55 +00:00
}
2010-07-01 23:48:07 +00:00
2010-12-03 05:09:55 +00:00
return false ;
2010-07-01 23:48:07 +00:00
}
2011-07-01 00:35:35 +00:00
function permissions_sql ( $owner_id , $remote_verified = false , $groups = null ) {
$local_user = local_user ();
$remote_user = remote_user ();
2012-03-07 01:52:00 +00:00
/**
* Construct permissions
*
* default permissions - anonymous user
*/
2017-01-09 12:09:01 +00:00
$sql = " AND allow_cid = ''
AND allow_gid = ''
AND deny_cid = ''
AND deny_gid = ''
2012-03-07 01:52:00 +00:00
" ;
/**
* Profile owner - everything is visible
*/
if (( $local_user ) && ( $local_user == $owner_id )) {
2017-01-09 12:09:01 +00:00
$sql = '' ;
2012-03-07 01:52:00 +00:00
}
/**
2017-01-09 12:09:01 +00:00
* Authenticated visitor . Unless pre - verified ,
2012-03-07 01:52:00 +00:00
* check that the contact belongs to this $owner_id
* and load the groups the visitor belongs to .
* If pre - verified , the caller is expected to have already
* done this and passed the groups into this function .
*/
elseif ( $remote_user ) {
if ( ! $remote_verified ) {
$r = q ( " SELECT id FROM contact WHERE id = %d AND uid = %d AND blocked = 0 LIMIT 1 " ,
intval ( $remote_user ),
intval ( $owner_id )
);
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r )) {
2012-03-07 01:52:00 +00:00
$remote_verified = true ;
$groups = init_groups_visitor ( $remote_user );
}
}
if ( $remote_verified ) {
2014-03-11 22:52:32 +00:00
2012-03-07 01:52:00 +00:00
$gs = '<<>>' ; // should be impossible to match
if ( is_array ( $groups ) && count ( $groups )) {
foreach ( $groups as $g )
$gs .= '|<' . intval ( $g ) . '>' ;
2017-01-09 12:09:01 +00:00
}
2012-03-07 01:52:00 +00:00
2012-09-29 23:54:37 +00:00
/* $sql = sprintf (
2017-01-09 12:09:01 +00:00
" AND ( allow_cid = '' OR allow_cid REGEXP '<%d>' )
AND ( deny_cid = '' OR NOT deny_cid REGEXP '<%d>' )
2012-03-07 01:52:00 +00:00
AND ( allow_gid = '' OR allow_gid REGEXP '%s' )
AND ( deny_gid = '' OR NOT deny_gid REGEXP '%s' )
" ,
intval ( $remote_user ),
intval ( $remote_user ),
dbesc ( $gs ),
dbesc ( $gs )
2012-09-29 23:54:37 +00:00
); */
$sql = sprintf (
" AND ( NOT (deny_cid REGEXP '<%d>' OR deny_gid REGEXP '%s')
AND ( allow_cid REGEXP '<%d>' OR allow_gid REGEXP '%s' OR ( allow_cid = '' AND allow_gid = '' ) )
)
" ,
intval ( $remote_user ),
dbesc ( $gs ),
intval ( $remote_user ),
dbesc ( $gs )
2012-03-07 01:52:00 +00:00
);
}
}
return $sql ;
}
function item_permissions_sql ( $owner_id , $remote_verified = false , $groups = null ) {
$local_user = local_user ();
$remote_user = remote_user ();
2011-07-01 00:35:35 +00:00
/**
* Construct permissions
*
* default permissions - anonymous user
*/
2014-03-09 08:19:14 +00:00
$sql = " AND `item`.allow_cid = ''
AND `item` . allow_gid = ''
AND `item` . deny_cid = ''
AND `item` . deny_gid = ''
AND `item` . private = 0
2011-07-01 00:35:35 +00:00
" ;
/**
* Profile owner - everything is visible
*/
2013-01-28 05:42:36 +00:00
if ( $local_user && ( $local_user == $owner_id )) {
$sql = '' ;
2011-07-01 00:35:35 +00:00
}
/**
2017-01-09 12:09:01 +00:00
* Authenticated visitor . Unless pre - verified ,
2011-07-01 00:35:35 +00:00
* check that the contact belongs to this $owner_id
* and load the groups the visitor belongs to .
* If pre - verified , the caller is expected to have already
* done this and passed the groups into this function .
*/
elseif ( $remote_user ) {
if ( ! $remote_verified ) {
$r = q ( " SELECT id FROM contact WHERE id = %d AND uid = %d AND blocked = 0 LIMIT 1 " ,
intval ( $remote_user ),
intval ( $owner_id )
);
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r )) {
2011-07-01 00:35:35 +00:00
$remote_verified = true ;
$groups = init_groups_visitor ( $remote_user );
}
}
if ( $remote_verified ) {
2014-03-09 08:19:14 +00:00
2011-07-01 00:35:35 +00:00
$gs = '<<>>' ; // should be impossible to match
if ( is_array ( $groups ) && count ( $groups )) {
foreach ( $groups as $g )
$gs .= '|<' . intval ( $g ) . '>' ;
2017-01-09 12:09:01 +00:00
}
2011-07-01 00:35:35 +00:00
$sql = sprintf (
2017-01-09 12:09:01 +00:00
/* " AND ( private = 0 OR ( private in (1,2) AND wall = 1 AND ( allow_cid = '' OR allow_cid REGEXP '<%d>' )
AND ( deny_cid = '' OR NOT deny_cid REGEXP '<%d>' )
2011-07-01 00:35:35 +00:00
AND ( allow_gid = '' OR allow_gid REGEXP '%s' )
2017-01-09 12:09:01 +00:00
AND ( deny_gid = '' OR NOT deny_gid REGEXP '%s' )))
2011-07-01 00:35:35 +00:00
" ,
intval ( $remote_user ),
intval ( $remote_user ),
dbesc ( $gs ),
dbesc ( $gs )
2013-02-05 03:27:30 +00:00
*/
2014-03-16 21:42:47 +00:00
" AND ( `item`.private = 0 OR ( `item`.private in (1,2) AND `item`.`wall` = 1
2014-03-09 08:19:14 +00:00
AND ( NOT ( `item` . deny_cid REGEXP '<%d>' OR `item` . deny_gid REGEXP '%s' )
2014-03-16 21:42:47 +00:00
AND ( `item` . allow_cid REGEXP '<%d>' OR `item` . allow_gid REGEXP '%s' OR ( `item` . allow_cid = '' AND `item` . allow_gid = '' )))))
2013-02-05 03:27:30 +00:00
" ,
intval ( $remote_user ),
dbesc ( $gs ),
intval ( $remote_user ),
dbesc ( $gs )
2011-07-01 00:35:35 +00:00
);
}
}
2012-03-09 08:31:17 +00:00
2011-07-01 00:35:35 +00:00
return $sql ;
2012-03-07 01:52:00 +00:00
}
2012-03-12 20:17:37 +00:00
/*
* Functions used to protect against Cross - Site Request Forgery
* The security token has to base on at least one value that an attacker can 't know - here it' s the session ID and the private key .
* In this implementation , a security token is reusable ( if the user submits a form , goes back and resubmits the form , maybe with small changes ;
* or if the security token is used for ajax - calls that happen several times ), but only valid for a certain amout of time ( 3 hours ) .
* The " typename " seperates the security tokens of different types of forms . This could be relevant in the following case :
* A security token is used to protekt a link from CSRF ( e . g . the " delete this profile " - link ) .
* If the new page contains by any chance external elements , then the used security token is exposed by the referrer .
* Actually , important actions should not be triggered by Links / GET - Requests at all , but somethimes they still are ,
* so this mechanism brings in some damage control ( the attacker would be able to forge a request to a form of this type , but not to forms of other types ) .
2017-01-09 12:09:01 +00:00
*/
2012-03-19 07:37:09 +00:00
function get_form_security_token ( $typename = '' ) {
2012-03-12 20:17:37 +00:00
$a = get_app ();
2017-01-09 12:09:01 +00:00
2012-03-12 20:17:37 +00:00
$timestamp = time ();
2012-03-19 07:37:09 +00:00
$sec_hash = hash ( 'whirlpool' , $a -> user [ 'guid' ] . $a -> user [ 'prvkey' ] . session_id () . $timestamp . $typename );
2017-01-09 12:09:01 +00:00
2012-03-19 07:37:09 +00:00
return $timestamp . '.' . $sec_hash ;
2012-03-12 20:17:37 +00:00
}
2012-03-19 07:37:09 +00:00
function check_form_security_token ( $typename = '' , $formname = 'form_security_token' ) {
2012-03-12 20:17:37 +00:00
if ( ! x ( $_REQUEST , $formname )) return false ;
$hash = $_REQUEST [ $formname ];
2017-01-09 12:09:01 +00:00
2012-03-12 20:17:37 +00:00
$max_livetime = 10800 ; // 3 hours
2017-01-09 12:09:01 +00:00
2012-03-12 20:17:37 +00:00
$a = get_app ();
2017-01-09 12:09:01 +00:00
2012-03-19 07:37:09 +00:00
$x = explode ( '.' , $hash );
2012-03-12 20:17:37 +00:00
if ( time () > ( IntVal ( $x [ 0 ]) + $max_livetime )) return false ;
2017-01-09 12:09:01 +00:00
2012-03-19 07:37:09 +00:00
$sec_hash = hash ( 'whirlpool' , $a -> user [ 'guid' ] . $a -> user [ 'prvkey' ] . session_id () . $x [ 0 ] . $typename );
2017-01-09 12:09:01 +00:00
2012-03-12 20:17:37 +00:00
return ( $sec_hash == $x [ 1 ]);
}
function check_form_security_std_err_msg () {
2012-04-14 20:24:35 +00:00
return t ( 'The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it.' ) . EOL ;
2012-03-12 20:17:37 +00:00
}
2012-03-19 07:37:09 +00:00
function check_form_security_token_redirectOnErr ( $err_redirect , $typename = '' , $formname = 'form_security_token' ) {
2012-03-12 20:17:37 +00:00
if ( ! check_form_security_token ( $typename , $formname )) {
$a = get_app ();
2012-03-19 07:37:09 +00:00
logger ( 'check_form_security_token failed: user ' . $a -> user [ 'guid' ] . ' - form element ' . $typename );
logger ( 'check_form_security_token failed: _REQUEST data: ' . print_r ( $_REQUEST , true ), LOGGER_DATA );
2012-03-12 20:17:37 +00:00
notice ( check_form_security_std_err_msg () );
2016-12-19 13:26:13 +00:00
goaway ( App :: get_baseurl () . $err_redirect );
2012-03-12 20:17:37 +00:00
}
}
2012-03-19 07:37:09 +00:00
function check_form_security_token_ForbiddenOnErr ( $typename = '' , $formname = 'form_security_token' ) {
2012-03-18 15:44:33 +00:00
if ( ! check_form_security_token ( $typename , $formname )) {
2012-04-17 11:33:50 +00:00
$a = get_app ();
2012-03-19 07:37:09 +00:00
logger ( 'check_form_security_token failed: user ' . $a -> user [ 'guid' ] . ' - form element ' . $typename );
logger ( 'check_form_security_token failed: _REQUEST data: ' . print_r ( $_REQUEST , true ), LOGGER_DATA );
2012-03-18 15:44:33 +00:00
header ( 'HTTP/1.1 403 Forbidden' );
killme ();
}
2012-04-14 20:24:35 +00:00
}
2012-10-21 21:41:10 +00:00
// Returns an array of group id's this contact is a member of.
// This array will only contain group id's related to the uid of this
2017-01-09 12:09:01 +00:00
// DFRN contact. They are *not* neccessarily unique across the entire site.
2012-10-21 21:41:10 +00:00
if ( ! function_exists ( 'init_groups_visitor' )) {
function init_groups_visitor ( $contact_id ) {
$groups = array ();
2017-01-09 12:09:01 +00:00
$r = q ( " SELECT `gid` FROM `group_member`
2012-10-21 21:41:10 +00:00
WHERE `contact-id` = % d " ,
intval ( $contact_id )
);
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r )) {
2012-10-21 21:41:10 +00:00
foreach ( $r as $rr )
$groups [] = $rr [ 'gid' ];
}
return $groups ;
}}