Merge branch 'feature-api' of alternc.org:alternc into feature-ssl

This commit is contained in:
Benjamin Sonntag 2014-09-21 16:44:32 +02:00
commit a3e2257b50
7 changed files with 101 additions and 31 deletions

View File

@ -2,7 +2,7 @@
/* Global variables (AlternC configuration) */ /* Global variables (AlternC configuration) */
require_once(__DIR__."/../../class/local.php"); require_once("/usr/share/alternc/panel/class/local.php");
// Define constants from vars of /etc/alternc/local.sh // Define constants from vars of /etc/alternc/local.sh
// The you can't choose where is the AlternC Panel // The you can't choose where is the AlternC Panel
@ -21,10 +21,9 @@ $root=ALTERNC_PANEL."/";
require_once($root."class/db_mysql.php"); require_once($root."class/db_mysql.php");
require_once($root."class/functions.php"); require_once($root."class/functions.php");
require_once($root."class/variables.php");
global $L_MYSQL_HOST,$L_MYSQL_DATABASE,$L_MYSQL_LOGIN,$L_MYSQL_PWD; global $L_MYSQL_HOST,$L_MYSQL_DATABASE,$L_MYSQL_LOGIN,$L_MYSQL_PWD,$db,$dbh;
class DB_system extends DB_Sql { class DB_system extends DB_Sql {
var $Host,$Database,$User,$Password; var $Host,$Database,$User,$Password;
@ -71,6 +70,7 @@ closedir($c);
/* Language */ /* Language */
//include_once("../../class/lang_env.php"); //include_once("../../class/lang_env.php");
$variables=new m_variables();
$mem=new m_mem(); $mem=new m_mem();
$err=new m_err(); $err=new m_err();
$authip=new m_authip(); $authip=new m_authip();

View File

@ -30,7 +30,72 @@ define("API_CALL_POST", 2 );
define("API_CALL_POST_REST", 3 ); define("API_CALL_POST_REST", 3 );
define("API_CALL_GET_REST", 4 ); define("API_CALL_GET_REST", 4 );
// TODO : __autoload of classes ? /**
* Attempts to load a class in multiple path, the PSR-0 or old style way
*
* @staticvar array $srcPathList
* @staticvar boolean $init
* @param string $class_name
* @return boolean
*/
function __autoload($class_name)
{
// Contains (Namespace) => directory
static $srcPathList = array();
static $init=null;
// Attempts to set include path and directories once
if( is_null( $init )){
// Sets init flag
$init = true;
// Sets a contextual directory
$srcPathList["standard"] = "/usr/share/php";
// Updates include_path according to this list
$includePathList = explode(PATH_SEPARATOR, get_include_path());
foreach($srcPathList as $path){
if ( !in_array($path, $includePathList)){
$includePathList[] = $path;
}
}
// Reverses the path for search efficiency
$finalIncludePathList = array_reverse($includePathList);
// Sets the updated include_path
set_include_path(implode(PATH_SEPARATOR, $finalIncludePathList));
}
// Accepts old Foo_Bar namespacing
if(preg_match("/_/", $class_name)){
$file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name) . '.php';
// Accepts 5.3 Foo\Bar PSR-0 namespacing
} else if(preg_match("/\\/", $class_name)){
$file_name = str_replace('\\', DIRECTORY_SEPARATOR, ltrim($class_name,'\\')) . '.php';
// Accepts non namespaced classes
} else {
$file_name = $class_name . '.php';
}
// Attempts to find file in namespace
foreach($srcPathList as $namespace => $path ){
$file_path = $path.DIRECTORY_SEPARATOR.$file_name;
if(is_file($file_path) && is_readable($file_path)){
require $file_path;
return true;
}
}
// Failed to find file
return false;
}
function apicall($data,$token,$mode) { function apicall($data,$token,$mode) {
global $dbh; global $dbh;
@ -38,7 +103,7 @@ function apicall($data,$token,$mode) {
$options["loginAdapterList"]=array("sharedsecret","login"); $options["loginAdapterList"]=array("sharedsecret","login");
// TODO (no loggerAdapter PSR3-Interface-compliant class as of now) // TODO (no loggerAdapter PSR3-Interface-compliant class as of now)
try { try {
$data["token_hash"]=$token;
$service=new Alternc_Api_Service($options); $service=new Alternc_Api_Service($options);
$response = $service->call( $response = $service->call(
@ -53,7 +118,7 @@ function apicall($data,$token,$mode) {
// something went wrong, we spit out the exception as an Api_Response // something went wrong, we spit out the exception as an Api_Response
// TODO : Don't do that on production! spit out a generic "fatal error" code and LOG the exception ! // TODO : Don't do that on production! spit out a generic "fatal error" code and LOG the exception !
header("Content-Type: application/json"); header("Content-Type: application/json");
$response=new Alternc_Api_Response(array("code" => $e->code, "message" => $e->message)); $response=new Alternc_Api_Response(array("code" => $e->getCode(), "message" => $e->getMessage() ));
echo $response->toJson(); echo $response->toJson();
exit(); exit();
} }
@ -85,7 +150,7 @@ function apiauth($data,$mode) {
// Authentication // Authentication
if (preg_match("#^/api/auth/([^/]*)/?#$",$_SERVER["REQUEST_URI"],$mat)) { if (preg_match("#^/api/auth/([^/\?]*)[/\?]?#",$_SERVER["REQUEST_URI"],$mat)) {
if ($_SERVER["REQUEST_METHOD"]=="POST") { if ($_SERVER["REQUEST_METHOD"]=="POST") {
$data=array("options" => $_POST, $data=array("options" => $_POST,
"method" => $mat[1]); "method" => $mat[1]);
@ -120,8 +185,7 @@ if ($_SERVER["REQUEST_URI"]=="/api/post") {
exit(); exit();
} }
} }
if (preg_match("#^/api/rest/([^/]*)/([^/\?]*)[/\?]?#",$_SERVER["REQUEST_URI"],$mat)) {
if (preg_match("#^/api/rest/([^/]*)/([^/]*)/?#$",$_SERVER["REQUEST_URI"],$mat)) {
if ($_SERVER["REQUEST_METHOD"]=="POST") { if ($_SERVER["REQUEST_METHOD"]=="POST") {
$data=array("options" => $_POST, $data=array("options" => $_POST,
"object" => $mat[1], "object" => $mat[1],
@ -140,3 +204,5 @@ if (preg_match("#^/api/rest/([^/]*)/([^/]*)/?#$",$_SERVER["REQUEST_URI"],$mat))
exit(); exit();
} }
} }
echo "I did nothing. Did you call the api properly?";

View File

@ -10,7 +10,7 @@ interface Alternc_Api_Auth_Interface {
* contructor : * contructor :
* $service is an Alternc_Api_Service object having a getDb() method * $service is an Alternc_Api_Service object having a getDb() method
*/ */
function __constructor($service); function __construct($service);
/** /**

View File

@ -12,8 +12,7 @@ class Alternc_Api_Auth_Sharedsecret implements Alternc_Api_Auth_Interface {
const ERR_INVALID_ARGUMENT = 1111801; const ERR_INVALID_ARGUMENT = 1111801;
const ERR_INVALID_SECRET = 1111802; const ERR_INVALID_SECRET = 1111802;
const ERR_INVALID_LOGIN = 1111803; const ERR_INVALID_LOGIN = 1111803;
const ERR_INVALID_LOGIN = 1111804; const ERR_DISABLED_ACCOUNT = 1111804;
const ERR_DISABLED_ACCOUNT = 1111805;
/** /**
@ -22,7 +21,7 @@ class Alternc_Api_Auth_Sharedsecret implements Alternc_Api_Auth_Interface {
* @param $service an Alternc_Api_Service object * @param $service an Alternc_Api_Service object
* @return create the object * @return create the object
*/ */
function __constructor($service) { function __construct($service) {
if (!($service instanceof Alternc_Api_Service)) if (!($service instanceof Alternc_Api_Service))
throw new \Exception("Invalid argument (service)",ERR_INVALID_ARGUMENT); throw new \Exception("Invalid argument (service)",ERR_INVALID_ARGUMENT);
@ -55,15 +54,16 @@ class Alternc_Api_Auth_Sharedsecret implements Alternc_Api_Auth_Interface {
return new Alternc_Api_Response( array("code" => self::ERR_INVALID_LOGIN, "message" => "Invalid login") ); return new Alternc_Api_Response( array("code" => self::ERR_INVALID_LOGIN, "message" => "Invalid login") );
} }
$stmt = $db->query("SELECT m.enabled,m.uid,m.login,m.su FROM membres m, sharedsecret s WHERE s.uid=m.uid AND m.login=? AND s.secret=?;",array($options["login"],$options["secret"]),PDO::FETCH_CLASS); $stmt = $this->db->prepare("SELECT m.enabled,m.uid,m.login,m.su FROM membres m, sharedsecret s WHERE s.uid=m.uid AND m.login=? AND s.secret=?;");
$me=$stmt->fetch(); $stmt->execute(array($options["login"],$options["secret"]) );
$me=$stmt->fetch(PDO::FETCH_OBJ);
if (!$me) if (!$me)
return new Alternc_Api_Response( array("code" => self::ERR_INVALID_AUTH, "message" => "Invalid shared secret") ); return new Alternc_Api_Response( array("code" => self::ERR_INVALID_AUTH, "message" => "Invalid shared secret") );
if (!$me->enabled) if (!$me->enabled)
return new Alternc_Api_Response( array("code" => self::ERR_DISABLED_ACCOUNT, "message" => "Account is disabled") ); return new Alternc_Api_Response( array("code" => self::ERR_DISABLED_ACCOUNT, "message" => "Account is disabled") );
return Alternc_Api_Token::tokenGenerate( return Alternc_Api_Token::tokenGenerate(
array("uid"=>$me->uid, "isAdmin"=>($me->su!=0) ), array("uid"=>(int)$me->uid, "isAdmin"=>($me->su!=0) ),
$this->db $this->db
); );
} }

View File

@ -46,7 +46,7 @@ class Alternc_Api_Response {
* initialize a response object * initialize a response object
* @param options any of the public above * @param options any of the public above
*/ */
public function __constructor($options=array()) { public function __construct($options=array()) {
$os=array("code","message","content","metadata"); $os=array("code","message","content","metadata");
foreach ($os as $o) { foreach ($os as $o) {
if (isset($options[$o])) $this->$o=$options[$o]; if (isset($options[$o])) $this->$o=$options[$o];

View File

@ -86,11 +86,12 @@ class Alternc_Api_Service {
if (count($this->allowedAuth) && !in_array($auth["method"],$this->allowedAuth)) { if (count($this->allowedAuth) && !in_array($auth["method"],$this->allowedAuth)) {
throw new \Exception("Method not allowed", self::ERR_METHOD_DENIED); throw new \Exception("Method not allowed", self::ERR_METHOD_DENIED);
} }
if (isset($auth["options"]["uid"]) && !is_int($auth["options"]["uid"])) { if (isset($auth["options"]["uid"]) && !intval($auth["options"]["uid"])) {
throw new \Exception("Invalid UID", self::ERR_INVALID_ARGUMENT); throw new \Exception("Invalid UID", self::ERR_INVALID_ARGUMENT);
} }
$adapterName = "Alternc_Api_Auth_".ucfirst(strtolower($auth["method"])); $adapterName = "Alternc_Api_Auth_".ucfirst(strtolower($auth["method"]));
$authAdapter = new $adapterName($this); $authAdapter = new $adapterName($this);
$token = $authAdapter->auth($auth["options"]); $token = $authAdapter->auth($auth["options"]);
@ -108,9 +109,10 @@ class Alternc_Api_Service {
return new Alternc_Api_Response( array("code" => self::ERR_SETUID_FORBIDDEN, "message" => "This user is not allowed to set his uid") ); return new Alternc_Api_Response( array("code" => self::ERR_SETUID_FORBIDDEN, "message" => "This user is not allowed to set his uid") );
} }
// Search for the requested user. We allow using *disabled* account here since we are admin // Search for the requested user. We allow using *disabled* account here since we are admin
foreach($db->query("SELECT uid FROM membres WHERE uid=?",array($auth["options"]["uid"])) as $setuid) { foreach($this->db->query("SELECT uid FROM membres WHERE uid=".intval($auth["options"]["uid"])) as $setuid) {
$token->uid=$setuid; $token->uid=intval($setuid['uid']);
$db->exec("UPDATE token SET uid=? WHERE token=?",array( $token->uid, $token->token) ); $stmt=$this->db->prepare("UPDATE token SET data=? WHERE token=?");
$stmt->execute(array( $token->toJson(), $token->token));
return $token; return $token;
} }
return new Alternc_Api_Response( array("code" => self::ERR_SETUID_USER_NOT_FOUND, "message" => "Can't find the user you want to setuid to") ); return new Alternc_Api_Response( array("code" => self::ERR_SETUID_USER_NOT_FOUND, "message" => "Can't find the user you want to setuid to") );
@ -148,7 +150,7 @@ class Alternc_Api_Service {
$request->token=$this->token; // we receive $request->token_hash as a STRING, but we transmit its object as an Alternc_Api_Token. $request->token=$this->token; // we receive $request->token_hash as a STRING, but we transmit its object as an Alternc_Api_Token.
// TODO: log this Api Call // TODO: log this Api Call
return $object->$action($request); return $object->$action($request->options);
} }

View File

@ -39,7 +39,7 @@ class Alternc_Api_Token {
* *
* @var int * @var int
*/ */
public static $tokenDuration = 2678400; // default is a month public $tokenDuration = 2678400; // default is a month
/** /**
@ -47,7 +47,7 @@ class Alternc_Api_Token {
* @param options any of the public above * @param options any of the public above
* may contain a dbAdapter, in that case create() will be available * may contain a dbAdapter, in that case create() will be available
*/ */
public function __constructor($options=array()) { public function __construct($options=array()) {
if (isset($options["uid"]) && is_int($options["uid"])) if (isset($options["uid"]) && is_int($options["uid"]))
$this->uid=$options["uid"]; $this->uid=$options["uid"];
@ -89,9 +89,10 @@ class Alternc_Api_Token {
do { do {
$token->token = $token->tokenRandom(); $token->token = $token->tokenRandom();
$rows = $db->exec("INSERT IGNORE INTO token SET token=?, expire=DATE_ADD(NOW(), INTERVAL ? SECONDS), data=?", $stmt=$db->prepare("INSERT IGNORE INTO token SET token=?, expire=DATE_ADD(NOW(), INTERVAL ? SECOND), data=?");
array($token,$token->tokenDuration, $token->toJson()) $stmt->execute(array($token->token,$token->tokenDuration, $token->toJson()));
); $rows = $stmt->rowCount();
} while ($rows==0); // prevent collisions } while ($rows==0); // prevent collisions
return $token; return $token;
@ -113,8 +114,9 @@ class Alternc_Api_Token {
if (!is_string($token) || !preg_match("#^[a-zA-Z0-9]{32}$#",$token)) { if (!is_string($token) || !preg_match("#^[a-zA-Z0-9]{32}$#",$token)) {
return new Alternc_Api_Response( array("code" => self::ERR_INVALID_TOKEN, "message" => "Invalid token") ); return new Alternc_Api_Response( array("code" => self::ERR_INVALID_TOKEN, "message" => "Invalid token") );
} }
$stmt=$db->prepare("SELECT * FROM token WHERE token=?");
foreach($db->query("SELECT * FROM token WHERE token=?", array($token)) as $tok) { $stmt->execute(array($token));
while ($tok=$stmt->fetch(PDO::FETCH_OBJ)) {
return new Alternc_Api_Token( json_decode($tok->data,true) ); return new Alternc_Api_Token( json_decode($tok->data,true) );
} }