2018-02-09 03:49:49 +00:00
< ? php
namespace Friendica ;
2018-10-17 19:30:41 +00:00
use Friendica\Core\L10n ;
2018-10-29 21:20:46 +00:00
use Friendica\Core\Logger ;
2018-10-17 19:30:41 +00:00
2018-02-09 03:49:49 +00:00
/**
* All modules in Friendica should extend BaseModule , although not all modules
* need to extend all the methods described here
*
2018-04-03 14:33:39 +00:00
* The filename of the module in src / Module needs to match the class name
* exactly to make the module available .
*
2018-09-15 23:28:38 +00:00
* @ author Hypolite Petovan < hypolite @ mrpetovan . com >
2018-02-09 03:49:49 +00:00
*/
abstract class BaseModule extends BaseObject
{
/**
* @ brief Initialization method common to both content () and post ()
*
* Extend this method if you need to do any shared processing before both
* content () or post ()
*/
2019-11-05 20:22:54 +00:00
public static function init ( $parameters )
2018-02-09 03:49:49 +00:00
{
2018-09-30 20:47:28 +00:00
}
2018-02-09 03:49:49 +00:00
2018-09-30 20:47:28 +00:00
/**
* @ brief Module GET method to display raw content from technical endpoints
*
* Extend this method if the module is supposed to return communication data ,
* e . g . from protocol implementations .
*/
2019-11-05 19:16:26 +00:00
public static function rawContent ( $parameters )
2018-09-30 20:47:28 +00:00
{
2018-02-09 03:49:49 +00:00
}
/**
* @ brief Module GET method to display any content
*
* Extend this method if the module is supposed to return any display
* through a GET request . It can be an HTML page through templating or a
* XML feed or a JSON output .
*
* @ return string
*/
2019-11-05 20:22:54 +00:00
public static function content ( $parameters )
2018-02-09 03:49:49 +00:00
{
$o = '' ;
return $o ;
}
/**
* @ brief Module POST method to process submitted data
*
* Extend this method if the module is supposed to process POST requests .
* Doesn ' t display any content
*/
2019-11-05 20:22:54 +00:00
public static function post ( $parameters )
2018-02-09 03:49:49 +00:00
{
}
/**
* @ brief Called after post ()
*
* Unknown purpose
*/
2019-11-05 20:22:54 +00:00
public static function afterpost ( $parameters )
2018-02-09 03:49:49 +00:00
{
}
2018-10-17 19:30:41 +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 ) .
*/
public static function getFormSecurityToken ( $typename = '' )
{
2018-12-28 00:22:35 +00:00
$a = \get_app ();
2018-10-17 19:30:41 +00:00
$timestamp = time ();
$sec_hash = hash ( 'whirlpool' , $a -> user [ 'guid' ] . $a -> user [ 'prvkey' ] . session_id () . $timestamp . $typename );
return $timestamp . '.' . $sec_hash ;
}
public static function checkFormSecurityToken ( $typename = '' , $formname = 'form_security_token' )
{
$hash = null ;
if ( ! empty ( $_REQUEST [ $formname ])) {
/// @TODO Careful, not secured!
$hash = $_REQUEST [ $formname ];
}
if ( ! empty ( $_SERVER [ 'HTTP_X_CSRF_TOKEN' ])) {
/// @TODO Careful, not secured!
$hash = $_SERVER [ 'HTTP_X_CSRF_TOKEN' ];
}
if ( empty ( $hash )) {
return false ;
}
$max_livetime = 10800 ; // 3 hours
2018-12-28 00:22:35 +00:00
$a = \get_app ();
2018-10-17 19:30:41 +00:00
$x = explode ( '.' , $hash );
2019-10-07 18:10:30 +00:00
if ( time () > ( intval ( $x [ 0 ]) + $max_livetime )) {
2018-10-17 19:30:41 +00:00
return false ;
}
$sec_hash = hash ( 'whirlpool' , $a -> user [ 'guid' ] . $a -> user [ 'prvkey' ] . session_id () . $x [ 0 ] . $typename );
return ( $sec_hash == $x [ 1 ]);
}
public static function getFormSecurityStandardErrorMessage ()
{
return L10n :: t ( " The form security token was not correct. This probably happened because the form has been opened for too long \x28 >3 hours \x29 before submitting it. " ) . EOL ;
}
public static function checkFormSecurityTokenRedirectOnError ( $err_redirect , $typename = '' , $formname = 'form_security_token' )
{
if ( ! self :: checkFormSecurityToken ( $typename , $formname )) {
2018-12-28 00:22:35 +00:00
$a = \get_app ();
2018-10-29 21:20:46 +00:00
Logger :: log ( 'checkFormSecurityToken failed: user ' . $a -> user [ 'guid' ] . ' - form element ' . $typename );
2018-10-30 13:58:45 +00:00
Logger :: log ( 'checkFormSecurityToken failed: _REQUEST data: ' . print_r ( $_REQUEST , true ), Logger :: DATA );
2018-10-19 08:03:52 +00:00
notice ( self :: getFormSecurityStandardErrorMessage ());
2018-10-19 18:11:27 +00:00
$a -> internalRedirect ( $err_redirect );
2018-10-17 19:30:41 +00:00
}
}
public static function checkFormSecurityTokenForbiddenOnError ( $typename = '' , $formname = 'form_security_token' )
{
if ( ! self :: checkFormSecurityToken ( $typename , $formname )) {
2018-12-28 00:22:35 +00:00
$a = \get_app ();
2018-10-29 21:20:46 +00:00
Logger :: log ( 'checkFormSecurityToken failed: user ' . $a -> user [ 'guid' ] . ' - form element ' . $typename );
2018-10-30 13:58:45 +00:00
Logger :: log ( 'checkFormSecurityToken failed: _REQUEST data: ' . print_r ( $_REQUEST , true ), Logger :: DATA );
2018-12-26 05:40:12 +00:00
2019-05-02 03:16:10 +00:00
throw new \Friendica\Network\HTTPException\ForbiddenException ();
2018-10-17 19:30:41 +00:00
}
}
2018-02-09 03:49:49 +00:00
}