2017-06-16 17:36:42 -06:00
< ? php
2017-12-16 13:27:09 -07:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http :// mozilla . org / MPL / 2.0 /. */
2017-06-16 17:36:42 -06:00
/*
* Mobile app API
*/
require __DIR__ . " /../required.php " ;
header ( 'Content-Type: application/json' );
2017-06-29 04:02:15 -06:00
header ( 'Access-Control-Allow-Origin: *' );
2017-06-16 17:36:42 -06:00
// Allow ping check without authentication
if ( $VARS [ 'action' ] == " ping " ) {
exit ( json_encode ([ " status " => " OK " ]));
}
2018-12-21 01:16:29 -07:00
if ( $SETTINGS [ 'mobile_enabled' ] !== TRUE ) {
2018-07-09 23:16:43 -06:00
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " mobile login disabled " , false )]));
2017-06-16 17:36:42 -06:00
}
// Make sure we have a username and access key
2018-12-14 19:13:26 -07:00
if ( empty ( $VARS [ 'username' ]) || empty ( $VARS [ 'key' ])) {
2017-06-16 17:36:42 -06:00
http_response_code ( 401 );
die ( json_encode ([ " status " => " ERROR " , " msg " => " Missing username and/or access key. " ]));
}
2017-07-03 03:00:23 -06:00
$username = strtolower ( $VARS [ 'username' ]);
$key = strtoupper ( $VARS [ 'key' ]);
2017-06-16 17:36:42 -06:00
// Make sure the username and key are actually legit
2018-11-08 21:19:25 -07:00
// Don't check key if we're trying to generate one
if ( $VARS [ 'action' ] == " generatesynccode " ) {
if ( ! User :: byUsername ( $username ) -> exists ()) {
Log :: insert ( LogType :: MOBILE_LOGIN_FAILED , null , " Username: " . $username . " , Key: " . $key );
die ( json_encode ([ " status " => " ERROR " , " msg " => " Invalid username and/or access key. " ]));
}
} else {
$user_key_valid = $database -> has ( 'mobile_codes' , [ '[>]accounts' => [ 'uid' => 'uid' ]], [ " AND " => [ 'mobile_codes.code' => $key , 'accounts.username' => $username ]]);
if ( $user_key_valid !== TRUE ) {
engageRateLimit ();
Log :: insert ( LogType :: MOBILE_BAD_KEY , null , " Username: " . $username . " , Key: " . $key );
die ( json_encode ([ " status " => " ERROR " , " msg " => " Invalid username and/or access key. " ]));
}
2017-06-16 17:36:42 -06:00
}
2017-10-11 13:16:35 -06:00
// Obscure key
if ( strlen ( $key ) > 7 ) {
for ( $i = 3 ; $i < strlen ( $key ) - 3 ; $i ++ ) {
$key [ $i ] = " * " ;
}
}
2017-06-16 17:36:42 -06:00
// Process the action
switch ( $VARS [ 'action' ]) {
case " check_key " :
// Check if the username/key combo is valid.
// If we get this far, it is, so return success.
exit ( json_encode ([ " status " => " OK " ]));
case " check_password " :
2017-06-16 21:07:01 -06:00
// Check if the user-supplied password is valid.
2017-06-16 18:40:12 -06:00
engageRateLimit ();
2018-07-11 23:32:47 -06:00
$user = User :: byUsername ( $username );
if ( $user -> getStatus () -> get () != AccountStatus :: NORMAL ) {
Log :: insert ( LogType :: MOBILE_LOGIN_FAILED , null , " Username: " . $username . " , Key: " . $key );
2018-07-09 23:16:43 -06:00
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " login failed try on web " , false )]));
2017-06-16 17:36:42 -06:00
}
2018-07-11 23:32:47 -06:00
if ( $user -> checkPassword ( $VARS [ 'password' ])) {
Log :: insert ( LogType :: MOBILE_LOGIN_OK , $user -> getUID (), " Key: " . $key );
exit ( json_encode ([ " status " => " OK " , " uid " => $user -> getUID ()]));
2017-06-16 17:36:42 -06:00
} else {
2018-07-11 23:32:47 -06:00
Log :: insert ( LogType :: MOBILE_LOGIN_FAILED , null , " Username: " . $username . " , Key: " . $key );
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " login incorrect " , false )]));
2017-06-16 17:36:42 -06:00
}
2017-06-29 04:02:15 -06:00
case " user_info " :
engageRateLimit ();
2018-07-11 23:32:47 -06:00
$user = User :: byUsername ( $username );
if ( $user -> getStatus () -> get () != AccountStatus :: NORMAL ) {
Log :: insert ( LogType :: MOBILE_LOGIN_FAILED , null , " Username: " . $username . " , Key: " . $key );
2018-07-09 23:16:43 -06:00
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " login failed try on web " , false )]));
2017-06-29 04:02:15 -06:00
}
2018-07-11 23:32:47 -06:00
if ( $user -> checkPassword ( $VARS [ 'password' ])) {
$userinfo = [ " uid " => $user -> getUID (), " username " => $user -> getUsername (), " realname " => $user -> getName (), " email " => $user -> getEmail ()];
Log :: insert ( LogType :: MOBILE_LOGIN_OK , $user -> getUID (), " Key: " . $key );
2017-06-29 04:02:15 -06:00
exit ( json_encode ([ " status " => " OK " , " info " => $userinfo ]));
} else {
2018-07-11 23:32:47 -06:00
Log :: insert ( LogType :: MOBILE_LOGIN_FAILED , null , " Username: " . $username . " , Key: " . $key );
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " login incorrect " , false )]));
2017-06-29 04:02:15 -06:00
}
2017-06-16 21:07:01 -06:00
case " start_session " :
// Do a web login.
engageRateLimit ();
2018-07-11 23:32:47 -06:00
$user = User :: byUsername ( $username );
if ( $user -> exists ()) {
if ( $user -> getStatus () -> get () == AccountStatus :: NORMAL ) {
if ( $user -> checkPassword ( $VARS [ 'password' ])) {
Session :: start ( $user );
2017-11-13 16:14:47 -07:00
$_SESSION [ 'mobile' ] = true ;
2017-06-16 21:07:01 -06:00
exit ( json_encode ([ " status " => " OK " ]));
}
}
}
2018-07-11 23:32:47 -06:00
Log :: insert ( LogType :: MOBILE_LOGIN_FAILED , null , " Username: " . $username . " , Key: " . $key );
2018-07-09 23:16:43 -06:00
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " login incorrect " , false )]));
2017-06-29 04:02:15 -06:00
case " listapps " :
2018-12-21 01:16:29 -07:00
$apps = $SETTINGS [ 'apps' ];
2017-08-06 16:09:26 -06:00
// Format paths as absolute URLs
foreach ( $apps as $k => $v ) {
if ( strpos ( $apps [ $k ][ 'url' ], " http " ) === FALSE ) {
2017-08-06 22:54:31 -06:00
$apps [ $k ][ 'url' ] = ( isset ( $_SERVER [ 'HTTPS' ]) ? " https " : " http " ) . " :// " . $_SERVER [ 'HTTP_HOST' ] . ( $_SERVER [ 'SERVER_PORT' ] != 80 || $_SERVER [ 'SERVER_PORT' ] != 443 ? " : " . $_SERVER [ 'SERVER_PORT' ] : " " ) . $apps [ $k ][ 'url' ];
2017-08-06 16:09:26 -06:00
}
}
exit ( json_encode ([ " status " => " OK " , " apps " => $apps ]));
2017-12-18 01:44:53 -07:00
case " gencode " :
engageRateLimit ();
2018-07-11 23:32:47 -06:00
$user = User :: byUsername ( $username );
2017-12-18 01:44:53 -07:00
$code = " " ;
do {
$code = random_int ( 100000 , 999999 );
} while ( $database -> has ( " onetimekeys " , [ " key " => $code ]));
2018-07-11 23:32:47 -06:00
$database -> insert ( " onetimekeys " , [ " key " => $code , " uid " => $user -> getUID (), " expires " => date ( " Y-m-d H:i:s " , strtotime ( " +1 minute " ))]);
2017-12-18 01:44:53 -07:00
$database -> delete ( " onetimekeys " , [ " expires[<] " => date ( " Y-m-d H:i:s " )]); // cleanup
exit ( json_encode ([ " status " => " OK " , " code " => $code ]));
2018-08-07 01:43:27 -06:00
case " checknotifications " :
if ( ! empty ( $VARS [ 'username' ])) {
$user = User :: byUsername ( $VARS [ 'username' ]);
} else if ( ! empty ( $VARS [ 'uid' ])) {
$user = new User ( $VARS [ 'uid' ]);
} else {
http_response_code ( 400 );
die ( " \" 400 Bad Request \" " );
}
try {
$notifications = Notifications :: get ( $user , false );
exit ( json_encode ([ " status " => " OK " , " notifications " => $notifications ]));
} catch ( Exception $ex ) {
exit ( json_encode ([ " status " => " ERROR " , " msg " => $ex -> getMessage ()]));
}
break ;
case " readnotification " :
if ( ! empty ( $VARS [ 'username' ])) {
$user = User :: byUsername ( $VARS [ 'username' ]);
} else if ( ! empty ( $VARS [ 'uid' ])) {
$user = new User ( $VARS [ 'uid' ]);
} else {
http_response_code ( 400 );
die ( " \" 400 Bad Request \" " );
}
if ( empty ( $VARS [ 'id' ])) {
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " invalid parameters " , false )]));
}
try {
Notifications :: read ( $user , $VARS [ 'id' ]);
exit ( json_encode ([ " status " => " OK " ]));
} catch ( Exception $ex ) {
exit ( json_encode ([ " status " => " ERROR " , " msg " => $ex -> getMessage ()]));
}
break ;
case " addnotification " :
if ( ! empty ( $VARS [ 'username' ])) {
$user = User :: byUsername ( $VARS [ 'username' ]);
} else if ( ! empty ( $VARS [ 'uid' ])) {
$user = new User ( $VARS [ 'uid' ]);
} else {
http_response_code ( 400 );
die ( " \" 400 Bad Request \" " );
}
try {
$timestamp = " " ;
if ( ! empty ( $VARS [ 'timestamp' ])) {
$timestamp = date ( " Y-m-d H:i:s " , strtotime ( $VARS [ 'timestamp' ]));
}
$url = " " ;
if ( ! empty ( $VARS [ 'url' ])) {
$url = $VARS [ 'url' ];
}
$nid = Notifications :: add ( $user , $VARS [ 'title' ], $VARS [ 'content' ], $timestamp , $url , isset ( $VARS [ 'sensitive' ]));
exit ( json_encode ([ " status " => " OK " , " id " => $nid ]));
} catch ( Exception $ex ) {
exit ( json_encode ([ " status " => " ERROR " , " msg " => $ex -> getMessage ()]));
}
break ;
case " deletenotification " :
if ( ! empty ( $VARS [ 'username' ])) {
$user = User :: byUsername ( $VARS [ 'username' ]);
} else if ( ! empty ( $VARS [ 'uid' ])) {
$user = new User ( $VARS [ 'uid' ]);
} else {
http_response_code ( 400 );
die ( " \" 400 Bad Request \" " );
}
if ( empty ( $VARS [ 'id' ])) {
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " invalid parameters " , false )]));
}
try {
Notifications :: delete ( $user , $VARS [ 'id' ]);
exit ( json_encode ([ " status " => " OK " ]));
} catch ( Exception $ex ) {
exit ( json_encode ([ " status " => " ERROR " , " msg " => $ex -> getMessage ()]));
}
break ;
2018-11-08 21:19:25 -07:00
case " hasotp " :
if ( ! empty ( $VARS [ 'username' ])) {
$user = User :: byUsername ( $VARS [ 'username' ]);
} else if ( ! empty ( $VARS [ 'uid' ])) {
$user = new User ( $VARS [ 'uid' ]);
} else {
http_response_code ( 400 );
die ( " \" 400 Bad Request \" " );
}
exit ( json_encode ([ " status " => " OK " , " otp " => $user -> has2fa ()]));
break ;
case " generatesynccode " :
$user = User :: byUsername ( $username );
if ( $user -> has2fa ()) {
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " 2-factor is enabled, you need to use the QR code or manual setup for security reasons " , false )]));
}
if ( $user -> getStatus () -> get () != AccountStatus :: NORMAL ) {
Log :: insert ( LogType :: MOBILE_LOGIN_FAILED , null , " Username: " . $username . " , Key: " . $key );
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " login failed try on web " , false )]));
}
if ( $user -> checkPassword ( $VARS [ 'password' ])) {
Log :: insert ( LogType :: MOBILE_LOGIN_OK , $user -> getUID (), " Key: " . $key );
$code = strtoupper ( substr ( md5 ( mt_rand () . uniqid ( " " , true )), 0 , 20 ));
$desc = htmlspecialchars ( $VARS [ 'desc' ]);
$database -> insert ( 'mobile_codes' , [ 'uid' => $user -> getUID (), 'code' => $code , 'description' => $desc ]);
exit ( json_encode ([ " status " => " OK " , " code " => $code ]));
} else {
Log :: insert ( LogType :: MOBILE_LOGIN_FAILED , null , " Username: " . $username . " , Key: " . $key );
exit ( json_encode ([ " status " => " ERROR " , " msg " => $Strings -> get ( " login incorrect " , false )]));
}
2017-06-16 17:36:42 -06:00
default :
http_response_code ( 404 );
die ( json_encode ([ " status " => " ERROR " , " msg " => " The requested action is not available. " ]));
2018-12-02 13:51:27 -07:00
}