2020-05-08 22:53:21 +00:00
< ? php
namespace EEPROM ;
2022-07-05 19:07:24 +00:00
require_once __DIR__ . '/../eeprom.php' ;
2020-05-08 22:53:21 +00:00
$reqMethod = $_SERVER [ 'REQUEST_METHOD' ];
$reqPath = '/' . trim ( parse_url ( $_SERVER [ 'REQUEST_URI' ], PHP_URL_PATH ), '/' );
header ( 'X-Powered-By: EEPROM' );
function eepromOriginAllowed ( string $origin ) : bool {
$origin = mb_strtolower ( parse_url ( $origin , PHP_URL_HOST ));
if ( $origin === $_SERVER [ 'HTTP_HOST' ])
return true ;
$allowed = Config :: get ( 'CORS' , 'origins' , []);
if ( empty ( $allowed ))
return true ;
return in_array ( $origin , $allowed );
}
2022-01-28 00:31:08 +00:00
if ( $_SERVER [ 'HTTP_HOST' ] !== Config :: get ( 'Uploads' , 'api_domain' )) {
2020-05-08 22:53:21 +00:00
$reqMethod = 'GET' ; // short domain is read only, prevent deleting
$reqPath = '/uploads/' . trim ( $reqPath , '/' );
$isShortDomain = true ;
}
if ( ! empty ( $_SERVER [ 'HTTP_ORIGIN' ])) {
if ( ! eepromOriginAllowed ( $_SERVER [ 'HTTP_ORIGIN' ])) {
http_response_code ( 403 );
return ;
}
header ( 'Access-Control-Allow-Origin: ' . $_SERVER [ 'HTTP_ORIGIN' ]);
header ( 'Vary: Origin' );
}
if ( $reqMethod === 'OPTIONS' ) {
http_response_code ( 204 );
if ( isset ( $isShortDomain ))
header ( 'Access-Control-Allow-Methods: OPTIONS, GET' );
else {
header ( 'Access-Control-Allow-Credentials: true' );
header ( 'Access-Control-Allow-Headers: Authorization' );
header ( 'Access-Control-Allow-Methods: OPTIONS, GET, POST, DELETE' );
}
return ;
}
if ( ! isset ( $isShortDomain ) && ! empty ( $_SERVER [ 'HTTP_AUTHORIZATION' ])) {
$authParts = explode ( ' ' , $_SERVER [ 'HTTP_AUTHORIZATION' ], 2 );
$authMethod = strval ( $authParts [ 0 ] ? ? '' );
$authToken = strval ( $authParts [ 1 ] ? ? '' );
2020-05-12 18:30:22 +00:00
$authClients = Config :: get ( 'Auth' , 'clients' , []);
foreach ( $authClients as $client ) {
$client = new $client ;
if ( $client -> getName () !== $authMethod )
continue ;
$authUserId = $client -> verifyToken ( $authToken );
break ;
2020-05-08 22:53:21 +00:00
}
if ( isset ( $authUserId ) && $authUserId > 0 )
2022-07-06 16:58:40 +00:00
User :: byId ( $db , $authUserId ) -> setActive ();
2020-05-08 22:53:21 +00:00
}
if ( preg_match ( '#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#' , $reqPath , $matches )) {
$getNormal = empty ( $matches [ 2 ]);
$getThumbnail = isset ( $matches [ 2 ]) && $matches [ 2 ] === '.t' ;
try {
2022-07-06 16:58:40 +00:00
$uploadInfo = Upload :: byId ( $db , $matches [ 1 ]);
2020-05-08 22:53:21 +00:00
} catch ( UploadNotFoundException $ex ) {
http_response_code ( 404 );
echo 'File not found.' ;
return ;
}
if ( $uploadInfo -> isDMCA ()) {
http_response_code ( 451 );
echo 'File is unavailable for copyright reasons.' ;
return ;
}
if ( $uploadInfo -> isDeleted () || $uploadInfo -> hasExpired ()) {
http_response_code ( 404 );
echo 'File not found.' ;
return ;
}
if ( $reqMethod === 'DELETE' ) {
if ( ! User :: hasActive ()) {
http_response_code ( 401 );
return ;
}
if ( User :: active () -> isRestricted ()
|| User :: active () -> getId () !== $uploadInfo -> getUserId ()) {
http_response_code ( 403 );
return ;
}
http_response_code ( 204 );
2022-07-06 16:58:40 +00:00
$uploadInfo -> delete ( $db , false );
2020-05-08 22:53:21 +00:00
return ;
}
if ( ! is_file ( $uploadInfo -> getPath ())) {
http_response_code ( 404 );
echo 'Data is missing.' ;
return ;
}
if ( $getNormal ) {
2022-07-06 16:58:40 +00:00
$uploadInfo -> bumpAccess ( $db );
$uploadInfo -> bumpExpiry ( $db );
2020-05-08 22:53:21 +00:00
}
2020-05-30 23:49:59 +00:00
$fileName = $uploadInfo -> getName ();
2020-05-08 22:53:21 +00:00
$contentType = $uploadInfo -> getType ();
if ( $contentType === 'application/octet-stream' || substr ( $contentType , 0 , 5 ) === 'text/' )
$contentType = 'text/plain' ;
$sourceDir = basename ( $getThumbnail ? PRM_THUMBS : PRM_UPLOADS );
2020-05-30 23:49:59 +00:00
if ( $getThumbnail && $uploadInfo -> supportsThumbnail ()) {
if ( ! is_file ( $uploadInfo -> getThumbPath ()))
$uploadInfo -> createThumbnail ();
$contentType = 'image/jpeg' ;
$fileName = pathinfo ( $fileName , PATHINFO_FILENAME ) . '-thumb.jpg' ;
2020-05-08 22:53:21 +00:00
}
header ( sprintf ( 'X-Accel-Redirect: /%s/%s' , $sourceDir , $uploadInfo -> getId ()));
header ( sprintf ( 'Content-Type: %s' , $contentType ));
2020-05-30 23:49:59 +00:00
header ( sprintf ( 'Content-Disposition: inline; filename="%s"' , addslashes ( $fileName )));
2020-05-08 22:53:21 +00:00
return ;
}
if ( preg_match ( '#^/uploads/([a-zA-Z0-9-_]{32})\.json/?$#' , $reqPath , $matches )) {
if ( isset ( $isShortDomain )) {
http_response_code ( 404 );
return ;
}
try {
2022-07-06 16:58:40 +00:00
$uploadInfo = Upload :: byId ( $db , $matches [ 1 ]);
2020-05-08 22:53:21 +00:00
} catch ( UploadNotFoundException $ex ) {
http_response_code ( 404 );
return ;
}
header ( 'Content-Type: application/json; charset=utf-8' );
echo json_encode ( $uploadInfo );
return ;
}
2022-07-05 19:07:24 +00:00
if ( $reqPath === '/eeprom.js' ) {
2020-05-12 15:19:18 +00:00
header ( 'Content-Type: application/javascript; charset=utf-8' );
2022-07-05 19:07:24 +00:00
echo file_get_contents ( PRM_ROOT . '/js/eeprom-v1.0.js' );
return ;
}
if ( $reqPath === '/test-v1.0.html' && PRM_DEBUG ) {
header ( 'Content-Type: text/html; charset=utf-8' );
$cookie = htmlspecialchars (( string ) filter_input ( INPUT_COOKIE , 'msz_auth' ));
echo <<< TEST
<! doctype html >
< input type = " file " id = " -eeprom-file " /> < button id = " -eeprom-abort " > Abort </ button > < progress id = " -eeprom-progress " min = " 0 " max = " 100 " value = " 0 " ></ progress > < span id = " -eeprom-progress-done " ></ span > < span id = " -eeprom-progress-total " ></ span >< br />
< div id = " -eeprom-history " ></ div >
< script src = " /eeprom.js " type = " text/javascript " ></ script >
< script type = " text/javascript " >
var eFile = document . getElementById ( '-eeprom-file' ),
eAbort = document . getElementById ( '-eeprom-abort' ),
eProgress = document . getElementById ( '-eeprom-progress' ),
eProgressD = document . getElementById ( '-eeprom-progress-done' ),
eProgressT = document . getElementById ( '-eeprom-progress-total' ),
eHistory = document . getElementById ( '-eeprom-history' ),
eTask = undefined ;
eAbort . onclick = function () {
if ( eTask )
eTask . abort ();
};
var eClient = new EEPROM ( 1 , '/uploads' , 'Misuzu {$cookie}' );
eFile . onchange = function () {
var task = eTask = eClient . createUpload ( this . files [ 0 ]);
task . onProgress = function ( progressInfo ) {
eProgress . value = progressInfo . progress ;
eProgressD . textContent = progressInfo . loaded ;
eProgressT . textContent = progressInfo . total ;
};
task . onFailure = function ( errorInfo ) {
if ( ! errorInfo . userAborted ) {
var errorText = 'Was unable to upload file.' ;
switch ( errorInfo . error ) {
case EEPROM . ERR_INVALID :
errorText = 'Upload request was invalid.' ;
break ;
case EEPROM . ERR_AUTH :
errorText = 'Upload authentication failed, refresh and try again.' ;
break ;
case EEPROM . ERR_ACCESS :
errorText = 'You\'re not allowed to upload files.' ;
break ;
case EEPROM . ERR_GONE :
errorText = 'Upload client has a configuration error or the server is gone.' ;
break ;
case EEPROM . ERR_DMCA :
errorText = 'This file has been uploaded before and was removed for copyright reasons, you cannot upload this file.' ;
break ;
case EEPROM . ERR_SERVER :
errorText = 'Upload server returned a critical error, try again later.' ;
break ;
case EEPROM . ERR_SIZE :
if ( errorInfo . maxSize < 1 )
errorText = 'Selected file is too large.' ;
else {
var _t = [ 'bytes' , 'KB' , 'MB' , 'GB' , 'TB' ],
_i = parseInt ( Math . floor ( Math . log ( errorInfo . maxSize ) / Math . log ( 1024 ))),
_s = Math . round ( errorInfo . maxSize / Math . pow ( 1024 , _i ), 2 );
errorText = 'Upload may not be larger than %1 %2.' . replace ( '%1' , _s ) . replace ( '%2' , _t [ _i ]);
}
break ;
}
alert ( errorText );
}
};
task . onComplete = function ( fileInfo ) {
eTask = undefined ;
var elem = document . createElement ( 'div' );
elem . id = fileInfo . id ;
var link = document . createElement ( 'a' );
link . textContent = fileInfo . id ;
link . href = fileInfo . url ;
link . target = '_blank' ;
elem . appendChild ( link );
elem . appendChild ( document . createTextNode ( ' ' ));
var del = document . createElement ( 'button' );
del . textContent = 'Delete' ;
del . onclick = function () {
var dTask = eClient . deleteUpload ( fileInfo );
dTask . onFailure = function ( reason ) {
alert ( 'Delete failed: ' + reason );
};
dTask . onSuccess = function () {
eHistory . removeChild ( elem );
};
dTask . start ();
};
elem . appendChild ( del );
elem . appendChild ( document . createTextNode ( ' ' ));
var json = document . createElement ( 'code' );
json . textContent = JSON . stringify ( fileInfo );
elem . appendChild ( json );
eHistory . appendChild ( elem );
};
task . start ();
};
</ script >
TEST ;
2020-05-12 15:19:18 +00:00
return ;
}
2020-05-08 22:53:21 +00:00
header ( 'Content-Type: text/plain; charset=us-ascii' );
2022-07-05 16:00:20 +00:00
if ( $reqPath === '/' || $reqPath === '/stats.json' ) {
2020-05-08 22:53:21 +00:00
$fileCount = 0 ;
$userCount = 0 ;
$totalSize = 0 ;
$uniqueTypes = 0 ;
2022-07-06 16:58:40 +00:00
$uploadStats = $db -> query ( 'SELECT COUNT(`upload_id`) AS `amount`, SUM(`upload_size`) AS `size`, COUNT(DISTINCT `upload_type`) AS `types` FROM `prm_uploads` WHERE `upload_deleted` IS NULL AND `upload_dmca` IS NULL' );
if ( $uploadStats -> next ()) {
$fileCount = $uploadStats -> getInteger ( 0 );
$totalSize = $uploadStats -> getInteger ( 1 );
$uniqueTypes = $uploadStats -> getInteger ( 2 );
2020-05-08 22:53:21 +00:00
}
2022-07-06 16:58:40 +00:00
$userStats = $db -> query ( 'SELECT COUNT(`user_id`) AS `amount` FROM `prm_users` WHERE `user_restricted` IS NULL' );
2020-05-08 22:53:21 +00:00
2022-07-06 16:58:40 +00:00
if ( $userStats -> next ())
$userCount = $userStats -> getInteger ( 0 );
2020-05-08 22:53:21 +00:00
2022-07-05 16:00:20 +00:00
if ( $reqPath === '/stats.json' ) {
2020-05-08 22:53:21 +00:00
header ( 'Content-Type: application/json; charset=utf-8' );
echo json_encode ([
2022-07-05 16:00:20 +00:00
'size' => $totalSize ,
'files' => $fileCount ,
'types' => $uniqueTypes ,
'members' => $userCount ,
2020-05-08 22:53:21 +00:00
]);
return ;
}
2022-07-05 16:00:20 +00:00
header ( 'Content-Type: text/html; charset=utf-8' );
header ( 'X-Accel-Redirect: /index.html' );
2020-05-08 22:53:21 +00:00
return ;
}
if ( $reqPath === '/uploads' ) {
if ( $reqMethod !== 'POST' ) {
http_response_code ( 405 );
return ;
}
try {
2022-07-06 16:58:40 +00:00
$appInfo = Application :: byId ( $db , filter_input ( INPUT_POST , 'src' , FILTER_VALIDATE_INT ));
2020-05-08 22:53:21 +00:00
} catch ( ApplicationNotFoundException $ex ) {
http_response_code ( 404 );
return ;
}
if ( ! User :: hasActive ()) {
http_response_code ( 401 );
return ;
}
$userInfo = User :: active ();
if ( $userInfo -> isRestricted ()) {
http_response_code ( 403 );
return ;
}
if ( empty ( $_FILES [ 'file' ][ 'tmp_name' ]) || ! is_file ( $_FILES [ 'file' ][ 'tmp_name' ])) {
http_response_code ( 400 );
return ;
}
$maxFileSize = $appInfo -> getSizeLimit ();
if ( $appInfo -> allowSizeMultiplier ())
$maxFileSize *= $userInfo -> getSizeMultiplier ();
$fileSize = filesize ( $_FILES [ 'file' ][ 'tmp_name' ]);
if ( $_FILES [ 'file' ][ 'size' ] !== $fileSize || $fileSize > $maxFileSize ) {
http_response_code ( 413 );
header ( 'Access-Control-Expose-Headers: X-EEPROM-Max-Size' );
header ( 'X-EEPROM-Max-Size: ' . $maxFileSize );
return ;
}
$hash = hash_file ( 'sha256' , $_FILES [ 'file' ][ 'tmp_name' ]);
2022-07-06 16:58:40 +00:00
$fileInfo = Upload :: byHash ( $db , $hash );
2020-05-08 22:53:21 +00:00
if ( $fileInfo !== null ) {
if ( $fileInfo -> isDMCA ()) {
http_response_code ( 451 );
return ;
}
if ( $fileInfo -> getUserId () !== $userInfo -> getId ()
|| $fileInfo -> getApplicationId () !== $appInfo -> getId ())
unset ( $fileInfo );
}
if ( ! empty ( $fileInfo )) {
if ( $fileInfo -> isDeleted ())
2022-07-06 16:58:40 +00:00
$fileInfo -> restore ( $db );
2020-05-08 22:53:21 +00:00
} else {
try {
$fileInfo = Upload :: create (
2022-07-06 16:58:40 +00:00
$db , $appInfo , $userInfo ,
2020-05-08 22:53:21 +00:00
$_FILES [ 'file' ][ 'name' ],
mime_content_type ( $_FILES [ 'file' ][ 'tmp_name' ]),
$fileSize , $hash ,
$appInfo -> getExpiry (), true
);
} catch ( UploadCreationFailedException $ex ) {
http_response_code ( 500 );
return ;
}
if ( ! move_uploaded_file ( $_FILES [ 'file' ][ 'tmp_name' ], $fileInfo -> getPath ())) {
http_response_code ( 500 );
return ;
}
}
http_response_code ( 201 );
header ( 'Content-Type: application/json; charset=utf-8' );
echo json_encode ( $fileInfo );
return ;
}
http_response_code ( 404 );