1
0
Fork 0
mirror of synced 2024-05-20 04:32:37 +12:00

Updated coding standards using PHP-CS-FIXER

This commit is contained in:
eldadfux 2019-09-06 20:10:41 +03:00
parent 586aa0bbd4
commit 6a5f54615a
14 changed files with 1036 additions and 1175 deletions

View file

@ -20,17 +20,16 @@ $utopia->get('/v1/account')
->label('sdk.method', 'get')
->label('sdk.description', 'Get currently logged in user data as JSON object.')
->action(
function() use ($response, &$user, $providers)
{
function () use ($response, &$user, $providers) {
$oauthKeys = [];
foreach($providers as $key => $provider) {
if(!$provider['enabled']) {
foreach ($providers as $key => $provider) {
if (!$provider['enabled']) {
continue;
}
$oauthKeys[] = 'oauth' . ucfirst($key);
$oauthKeys[] = 'oauth' . ucfirst($key) . 'AccessToken';
$oauthKeys[] = 'oauth'.ucfirst($key);
$oauthKeys[] = 'oauth'.ucfirst($key).'AccessToken';
}
$response->json(array_merge($user->getArrayCopy(array_merge(
@ -52,17 +51,16 @@ $utopia->get('/v1/account/prefs')
->label('sdk.method', 'getPrefs')
->label('sdk.description', 'Get currently logged in user preferences key-value object.')
->action(
function() use ($response, $user) {
$prefs = $user->getAttribute('prefs', '{}');
function () use ($response, $user) {
$prefs = $user->getAttribute('prefs', '{}');
if(empty($prefs)) {
if (empty($prefs)) {
$prefs = '[]';
}
try {
$prefs = json_decode($prefs, true);
}
catch (\Exception $error) {
} catch (\Exception $error) {
throw new Exception('Failed to parse prefs', 500);
}
@ -77,20 +75,20 @@ $utopia->get('/v1/account/sessions')
->label('sdk.method', 'getSessions')
->label('sdk.description', 'Get currently logged in user list of active sessions across different devices.')
->action(
function() use ($response, $user) {
$tokens = $user->getAttribute('tokens', []);
$reader = new Reader(__DIR__ . '/../db/GeoLite2/GeoLite2-Country.mmdb');
$sessions = [];
$current = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_LOGIN, Auth::$secret);
$index = 0;
$countries = Locale::getText('countries');
function () use ($response, $user) {
$tokens = $user->getAttribute('tokens', []);
$reader = new Reader(__DIR__.'/../db/GeoLite2/GeoLite2-Country.mmdb');
$sessions = [];
$current = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_LOGIN, Auth::$secret);
$index = 0;
$countries = Locale::getText('countries');
foreach($tokens as $token) { /* @var $token Document */
if(Auth::TOKEN_TYPE_LOGIN != $token->getAttribute('type')) {
foreach ($tokens as $token) { /* @var $token Document */
if (Auth::TOKEN_TYPE_LOGIN != $token->getAttribute('type')) {
continue;
}
$userAgent = (!empty($token->getAttribute('userAgent'))) ? $token->getAttribute('userAgent') : 'UNKNOWN';
$userAgent = (!empty($token->getAttribute('userAgent'))) ? $token->getAttribute('userAgent') : 'UNKNOWN';
$dd = new DeviceDetector($userAgent);
@ -100,28 +98,27 @@ $utopia->get('/v1/account/sessions')
$dd->parse();
$sessions[$index] = [
'id' => $token->getUid(),
'OS' => $dd->getOs(),
'client' => $dd->getClient(),
'device' => $dd->getDevice(),
'brand' => $dd->getBrand(),
'model' => $dd->getModel(),
'ip' => $token->getAttribute('ip', ''),
'geo' => [],
'current' => ($current == $token->getUid()) ? true : false,
'id' => $token->getUid(),
'OS' => $dd->getOs(),
'client' => $dd->getClient(),
'device' => $dd->getDevice(),
'brand' => $dd->getBrand(),
'model' => $dd->getModel(),
'ip' => $token->getAttribute('ip', ''),
'geo' => [],
'current' => ($current == $token->getUid()) ? true : false,
];
try {
$record = $reader->country($token->getAttribute('ip', ''));
$sessions[$index]['geo']['isoCode'] = strtolower($record->country->isoCode);
$sessions[$index]['geo']['country'] = (isset($countries[$record->country->isoCode])) ? $countries[$record->country->isoCode] : Locale::getText('locale.country.unknown');
}
catch(\Exception $e) {
} catch (\Exception $e) {
$sessions[$index]['geo']['isoCode'] = '--';
$sessions[$index]['geo']['country'] = Locale::getText('locale.country.unknown');
}
$index++;
++$index;
}
$response->json($sessions);
@ -135,12 +132,12 @@ $utopia->get('/v1/account/security')
->label('sdk.method', 'getSecurity')
->label('sdk.description', 'Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.')
->action(
function() use ($response, $register, $project, $user) {
function () use ($response, $register, $project, $user) {
$ad = new \Audit\Adapter\MySQL($register->get('db'));
$ad->setNamespace('app_' . $project->getUid());
$ad->setNamespace('app_'.$project->getUid());
$au = new \Audit\Audit($ad, $user->getUid(), $user->getAttribute('type'), '', '', '');
$countries = Locale::getText('countries');
$countries = Locale::getText('countries');
$logs = $au->getLogsByUserAndActions($user->getUid(), $user->getAttribute('type', 0), [
'auth.register',
@ -159,11 +156,11 @@ $utopia->get('/v1/account/security')
'account.update.password',
]);
$reader = new Reader(__DIR__ . '/../db/GeoLite2/GeoLite2-Country.mmdb');
$output = [];
$reader = new Reader(__DIR__.'/../db/GeoLite2/GeoLite2-Country.mmdb');
$output = [];
foreach($logs as $i => &$log) {
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
foreach ($logs as $i => &$log) {
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
$dd = new DeviceDetector($log['userAgent']);
@ -172,15 +169,15 @@ $utopia->get('/v1/account/security')
$dd->parse();
$output[$i] = [
'event' => $log['event'],
'ip' => $log['ip'],
'time' => strtotime($log['time']),
'OS' => $dd->getOs(),
'client' => $dd->getClient(),
'device' => $dd->getDevice(),
'brand' => $dd->getBrand(),
'model' => $dd->getModel(),
'geo' => [],
'event' => $log['event'],
'ip' => $log['ip'],
'time' => strtotime($log['time']),
'OS' => $dd->getOs(),
'client' => $dd->getClient(),
'device' => $dd->getDevice(),
'brand' => $dd->getBrand(),
'model' => $dd->getModel(),
'geo' => [],
];
try {
@ -188,10 +185,9 @@ $utopia->get('/v1/account/security')
$output[$i]['geo']['isoCode'] = strtolower($record->country->isoCode);
$output[$i]['geo']['country'] = $record->country->name;
$output[$i]['geo']['country'] = (isset($countries[$record->country->isoCode])) ? $countries[$record->country->isoCode] : Locale::getText('locale.country.unknown');
}
catch(\Exception $e) {
} catch (\Exception $e) {
$output[$i]['geo']['isoCode'] = '--';
$output[$i]['geo']['country'] = Locale::getText('locale.country.unknown');;
$output[$i]['geo']['country'] = Locale::getText('locale.country.unknown');
}
}
@ -208,13 +204,12 @@ $utopia->patch('/v1/account/name')
->label('sdk.description', 'Update currently logged in user account name.')
->param('name', '', function () {return new Text(100);}, 'User name')
->action(
function($name) use ($response, $user, $projectDB, $audit)
{
function ($name) use ($response, $user, $projectDB, $audit) {
$user = $projectDB->updateDocument(array_merge($user->getArrayCopy(), [
'name' => $name,
]));
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
@ -234,9 +229,8 @@ $utopia->patch('/v1/account/password')
->param('password', '', function () {return new Password();}, 'New password')
->param('old-password', '', function () {return new Password();}, 'Old password')
->action(
function($password, $oldPassword) use ($response, $user, $projectDB, $audit)
{
if(!Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password
function ($password, $oldPassword) use ($response, $user, $projectDB, $audit) {
if (!Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password
throw new Exception('Invalid credentials', 401);
}
@ -244,7 +238,7 @@ $utopia->patch('/v1/account/password')
'password' => Auth::passwordHash($password),
]));
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
@ -264,9 +258,8 @@ $utopia->patch('/v1/account/email')
->param('email', '', function () {return new Email();}, 'Email Address')
->param('password', '', function () {return new Password();}, 'User Password')
->action(
function($email, $password) use ($response, $user, $projectDB, $audit)
{
if(!Auth::passwordVerify($password, $user->getAttribute('password'))) { // Double check user password
function ($email, $password) use ($response, $user, $projectDB, $audit) {
if (!Auth::passwordVerify($password, $user->getAttribute('password'))) { // Double check user password
throw new Exception('Invalid credentials', 401);
}
@ -274,12 +267,12 @@ $utopia->patch('/v1/account/email')
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'email=' . $email
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'email='.$email,
],
]);
if(!empty($profile)) {
if (!empty($profile)) {
throw new Exception('User already registered', 400);
}
@ -289,7 +282,7 @@ $utopia->patch('/v1/account/email')
'email' => $email,
]));
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
@ -308,13 +301,12 @@ $utopia->patch('/v1/account/prefs')
->param('prefs', '', function () {return new \Utopia\Validator\Mock();}, 'Prefs key-value JSON object string.')
->label('sdk.description', 'Update currently logged in user account preferences. You can pass only the specific settings you wish to update.')
->action(
function($prefs) use ($response, $user, $projectDB, $audit)
{
function ($prefs) use ($response, $user, $projectDB, $audit) {
$user = $projectDB->updateDocument(array_merge($user->getArrayCopy(), [
'prefs' => json_encode(array_merge(json_decode($user->getAttribute('prefs', '{}'), true), $prefs)),
]));
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
@ -332,19 +324,18 @@ $utopia->delete('/v1/account')
->label('sdk.method', 'delete')
->label('sdk.description', 'Delete currently logged in user account.')
->action(
function() use ($response, $request, $user, $projectDB, $audit)
{
function () use ($response, $request, $user, $projectDB, $audit) {
$user = $projectDB->updateDocument(array_merge($user->getArrayCopy(), [
'status' => Auth::USER_STATUS_BLOCKED,
]));
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
//TODO delete all tokens or only current session?
//TODO delete all user data according to GDPR. Make sure everything is backed up and backups are deleted later
/**
/*
* Data to delete
* * Tokens
* * Memberships
@ -364,4 +355,4 @@ $utopia->delete('/v1/account')
->addCookie(Auth::$cookieName, '', time() - 3600, '/', COOKIE_DOMAIN, ('https' == $request->getServer('REQUEST_SCHEME', 'https')), true)
->json(array('result' => 'success'));
}
);
);

View file

@ -35,20 +35,20 @@ $utopia->post('/v1/auth/register')
->param('success', null, function () use ($clients) {return new Host($clients);}, 'Redirect when registration succeed', true)
->param('failure', null, function () use ($clients) {return new Host($clients);}, 'Redirect when registration failed', true)
->action(
function($email, $password, $name, $redirect, $success, $failure) use ($request, $response, $register, $audit, $projectDB, $project, $webhook)
{
function ($email, $password, $name, $redirect, $success, $failure) use ($request, $response, $register, $audit, $projectDB, $project, $webhook) {
$profile = $projectDB->getCollection([ // Get user by email address
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'email=' . $email
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'email='.$email,
],
]);
if(!empty($profile)) {
if($failure) {
if (!empty($profile)) {
if ($failure) {
$response->redirect($failure);
return;
}
@ -79,36 +79,36 @@ $utopia->post('/v1/auth/register')
Authorization::enable();
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
Authorization::setRole('user:' . $user->getUid());
Authorization::setRole('user:'.$user->getUid());
$user
->setAttribute('tokens', new Document([
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:' . $user->getUid()], 'write' => ['user:' . $user->getUid()]],
'$permissions' => ['read' => ['user:'.$user->getUid()], 'write' => ['user:'.$user->getUid()]],
'type' => Auth::TOKEN_TYPE_CONFIRM,
'secret' => Auth::hash($confirmSecret), // On way hash encryption to protect DB leak
'expire' => time() + Auth::TOKEN_EXPIRATION_CONFIRM,
'userAgent' => $request->getServer('HTTP_USER_AGENT', 'UNKNOWN'),
'ip' => $request->getIP(),
]),Document::SET_TYPE_APPEND)
]), Document::SET_TYPE_APPEND)
->setAttribute('tokens', new Document([
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:' . $user->getUid()], 'write' => ['user:' . $user->getUid()]],
'$permissions' => ['read' => ['user:'.$user->getUid()], 'write' => ['user:'.$user->getUid()]],
'type' => Auth::TOKEN_TYPE_LOGIN,
'secret' => Auth::hash($loginSecret), // On way hash encryption to protect DB leak
'expire' => $expiry,
'userAgent' => $request->getServer('HTTP_USER_AGENT', 'UNKNOWN'),
'ip' => $request->getIP(),
]),Document::SET_TYPE_APPEND)
]), Document::SET_TYPE_APPEND)
;
$user = $projectDB->createDocument($user->getArrayCopy());
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving tokens to DB', 500);
}
@ -118,7 +118,7 @@ $utopia->post('/v1/auth/register')
$redirect['query'] = Template::mergeQuery(((isset($redirect['query'])) ? $redirect['query'] : ''), ['userId' => $user->getUid(), 'token' => $confirmSecret]);
$redirect = Template::unParseURL($redirect);
$body = new Template(__DIR__ . '/../config/locale/templates/' . Locale::getText('auth.emails.confirm.body'));
$body = new Template(__DIR__.'/../config/locale/templates/'.Locale::getText('auth.emails.confirm.body'));
$body
->setParam('{{direction}}', Locale::getText('settings.direction'))
->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]']))
@ -131,13 +131,12 @@ $utopia->post('/v1/auth/register')
$mail->addAddress($email, $name);
$mail->Subject = Locale::getText('auth.emails.confirm.title');
$mail->Body = $body->render();
$mail->Body = $body->render();
$mail->AltBody = strip_tags($body->render());
try {
$mail->send();
}
catch(\Exception $error) {
} catch (\Exception $error) {
// if($failure) {
// $response->redirect($failure);
// return;
@ -160,7 +159,7 @@ $utopia->post('/v1/auth/register')
$response->addCookie(Auth::$cookieName, Auth::encodeSession($user->getUid(), $loginSecret), $expiry, '/', COOKIE_DOMAIN, ('https' == $request->getServer('REQUEST_SCHEME', 'https')), true);
if($success) {
if ($success) {
$response->redirect($success);
}
@ -174,30 +173,29 @@ $utopia->post('/v1/auth/register/confirm')
->label('scope', 'public')
->label('sdk.namespace', 'auth')
->label('sdk.method', 'confirm')
->label('sdk.description', "Use this endpoint to complete the confirmation of the user account email address. Both the **userId** and **token** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the /auth/register endpoint.")
->label('sdk.description', 'Use this endpoint to complete the confirmation of the user account email address. Both the **userId** and **token** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the /auth/register endpoint.')
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},userId:{param-userId}')
->param('userId', '', function () {return new UID();}, 'User unique ID')
->param('token', '', function () {return new Text(256);}, 'Confirmation secret token')
->action(
function($userId, $token) use ($response, $request, $projectDB, $audit)
{
function ($userId, $token) use ($response, $request, $projectDB, $audit) {
$profile = $projectDB->getCollection([ // Get user by email address
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'$uid=' . $userId
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'$uid='.$userId,
],
]);
if(empty($profile)) {
if (empty($profile)) {
throw new Exception('User not found', 404); // TODO maybe hide this
}
$token = Auth::tokenVerify($profile->getAttribute('tokens', []), Auth::TOKEN_TYPE_CONFIRM, $token);
if(!$token) {
if (!$token) {
throw new Exception('Confirmation token is not valid', 401);
}
@ -206,11 +204,11 @@ $utopia->post('/v1/auth/register/confirm')
'confirm' => true,
]));
if(false === $profile) {
if (false === $profile) {
throw new Exception('Failed saving user to DB', 500);
}
if(!$projectDB->deleteDocument($token)) {
if (!$projectDB->deleteDocument($token)) {
throw new Exception('Failed to remove token from DB', 500);
}
@ -230,9 +228,8 @@ $utopia->post('/v1/auth/register/confirm/resend')
->label('abuse-key', 'url:{url},userId:{param-userId}')
->param('redirect', '', function () use ($clients) {return new Host($clients);}, 'Confirmation page to redirect user to your app after confirm token has been sent to user email.')
->action(
function($redirect) use ($response, $request, $projectDB, $user, $register, $project)
{
if($user->getAttribute('confirm', false)) {
function ($redirect) use ($response, $request, $projectDB, $user, $register, $project) {
if ($user->getAttribute('confirm', false)) {
throw new Exception('Email address is already confirmed', 400);
}
@ -240,7 +237,7 @@ $utopia->post('/v1/auth/register/confirm/resend')
$user->setAttribute('tokens', new Document([
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:' . $user->getUid()], 'write' => ['user:' . $user->getUid()]],
'$permissions' => ['read' => ['user:'.$user->getUid()], 'write' => ['user:'.$user->getUid()]],
'type' => Auth::TOKEN_TYPE_CONFIRM,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => time() + Auth::TOKEN_EXPIRATION_CONFIRM,
@ -250,7 +247,7 @@ $utopia->post('/v1/auth/register/confirm/resend')
$user = $projectDB->updateDocument($user->getArrayCopy());
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
@ -258,7 +255,7 @@ $utopia->post('/v1/auth/register/confirm/resend')
$redirect['query'] = Template::mergeQuery(((isset($redirect['query'])) ? $redirect['query'] : ''), ['userId' => $user->getUid(), 'token' => $secret]);
$redirect = Template::unParseURL($redirect);
$body = new Template(__DIR__ . '/../config/locale/templates/' . Locale::getText('auth.emails.confirm.body'));
$body = new Template(__DIR__.'/../config/locale/templates/'.Locale::getText('auth.emails.confirm.body'));
$body
->setParam('{{direction}}', Locale::getText('settings.direction'))
->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]']))
@ -271,13 +268,12 @@ $utopia->post('/v1/auth/register/confirm/resend')
$mail->addAddress($user->getAttribute('email'), $user->getAttribute('name'));
$mail->Subject = Locale::getText('auth.emails.confirm.title');
$mail->Body = $body->render();
$mail->Body = $body->render();
$mail->AltBody = strip_tags($body->render());
try {
$mail->send();
}
catch(\Exception $error) {
} catch (\Exception $error) {
//throw new Exception('Problem sending mail: ' . $error->getError(), 500);
}
@ -300,26 +296,25 @@ $utopia->post('/v1/auth/login')
->param('success', null, function () use ($clients) {return new Host($clients);}, 'URL to redirect back to your app after a successful login attempt.', true)
->param('failure', null, function () use ($clients) {return new Host($clients);}, 'URL to redirect back to your app after a failed login attempt.', true)
->action(
function($email, $password, $success, $failure) use ($response, $request, $projectDB, $audit, $webhook)
{
function ($email, $password, $success, $failure) use ($response, $request, $projectDB, $audit, $webhook) {
$profile = $projectDB->getCollection([ // Get user by email address
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'email=' . $email
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'email='.$email,
],
]);
if(!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) {
if (!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) {
$audit
//->setParam('userId', $profile->getUid())
->setParam('event', 'auth.failure')
;
if($failure) {
if ($failure) {
$response->redirect($failure);
return;
}
@ -331,19 +326,19 @@ $utopia->post('/v1/auth/login')
$profile->setAttribute('tokens', new Document([
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:' . $profile->getUid()], 'write' => ['user:' . $profile->getUid()]],
'$permissions' => ['read' => ['user:'.$profile->getUid()], 'write' => ['user:'.$profile->getUid()]],
'type' => Auth::TOKEN_TYPE_LOGIN,
'secret' => Auth::hash($secret), // On way hash encryption to protect DB leak
'expire' => $expiry,
'userAgent' => $request->getServer('HTTP_USER_AGENT', 'UNKNOWN'),
'ip' => $request->getIP(),
]),Document::SET_TYPE_APPEND);
]), Document::SET_TYPE_APPEND);
Authorization::setRole('user:' . $profile->getUid());
Authorization::setRole('user:'.$profile->getUid());
$profile = $projectDB->updateDocument($profile->getArrayCopy());
if(false === $profile) {
if (false === $profile) {
throw new Exception('Failed saving user to DB', 500);
}
@ -362,13 +357,12 @@ $utopia->post('/v1/auth/login')
$response
->addCookie(Auth::$cookieName, Auth::encodeSession($profile->getUid(), $secret), $expiry, '/', COOKIE_DOMAIN, ('https' == $request->getServer('REQUEST_SCHEME', 'https')), true);
if($success) {
if ($success) {
$response->redirect($success);
}
$response
->json(array('result' => 'success'));
;
}
);
@ -381,11 +375,10 @@ $utopia->delete('/v1/auth/logout')
->label('sdk.description', 'Use this endpoint to log out the currently logged in user from his account. When succeed this endpoint will delete the user session and remove the session secret cookie.')
->label('abuse-limit', 100)
->action(
function() use ($response, $request, $user, $projectDB, $audit, $webhook)
{
function () use ($response, $request, $user, $projectDB, $audit, $webhook) {
$token = Auth::tokenVerify($user->getAttribute('tokens'), Auth::TOKEN_TYPE_LOGIN, Auth::$secret);
if(!$projectDB->deleteDocument($token)) {
if (!$projectDB->deleteDocument($token)) {
throw new Exception('Failed to remove token from DB', 500);
}
@ -414,23 +407,21 @@ $utopia->delete('/v1/auth/logout/:id')
->label('abuse-limit', 100)
->param('id', null, function () {return new UID();}, 'User specific session unique ID number. if 0 delete all sessions.')
->action(
function($id) use ($response, $request, $user, $projectDB, $audit)
{
function ($id) use ($response, $request, $user, $projectDB, $audit) {
$tokens = $user->getAttribute('tokens', []);
foreach($tokens as $token) { /* @var $token Document */
if(($id == $token->getUid() || ($id == 0)) && Auth::TOKEN_TYPE_LOGIN == $token->getAttribute('type')) {
if(!$projectDB->deleteDocument($token->getUid())) {
foreach ($tokens as $token) { /* @var $token Document */
if (($id == $token->getUid() || ($id == 0)) && Auth::TOKEN_TYPE_LOGIN == $token->getAttribute('type')) {
if (!$projectDB->deleteDocument($token->getUid())) {
throw new Exception('Failed to remove token from DB', 500);
}
$audit
->setParam('event', 'auth.logout')
->setParam('resource', '/auth/token/' . $token->getUid())
->setParam('resource', '/auth/token/'.$token->getUid())
;
if($token->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete cookies
if ($token->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete cookies
$response->addCookie(Auth::$cookieName, '', time() - 3600, '/', COOKIE_DOMAIN, ('https' == $request->getServer('REQUEST_SCHEME', 'https')), true);
}
}
@ -451,18 +442,17 @@ $utopia->post('/v1/auth/recovery')
->param('email', '', function () {return new Email();}, 'User account email address.')
->param('redirect', '', function () use ($clients) {return new Host($clients);}, 'Reset page in your app to redirect user after reset token has been sent to user email.')
->action(
function($email, $redirect) use ($request, $response, $projectDB, $register, $audit, $project)
{
function ($email, $redirect) use ($request, $response, $projectDB, $register, $audit, $project) {
$profile = $projectDB->getCollection([ // Get user by email address
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'email=' . $email
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'email='.$email,
],
]);
if(empty($profile)) {
if (empty($profile)) {
throw new Exception('User not found', 404); // TODO maybe hide this
}
@ -470,7 +460,7 @@ $utopia->post('/v1/auth/recovery')
$profile->setAttribute('tokens', new Document([
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:' . $profile->getUid()], 'write' => ['user:' . $profile->getUid()]],
'$permissions' => ['read' => ['user:'.$profile->getUid()], 'write' => ['user:'.$profile->getUid()]],
'type' => Auth::TOKEN_TYPE_RECOVERY,
'secret' => Auth::hash($secret), // On way hash encryption to protect DB leak
'expire' => time() + Auth::TOKEN_EXPIRATION_RECOVERY,
@ -478,11 +468,11 @@ $utopia->post('/v1/auth/recovery')
'ip' => $request->getIP(),
]), Document::SET_TYPE_APPEND);
Authorization::setRole('user:' . $profile->getUid());
Authorization::setRole('user:'.$profile->getUid());
$profile = $projectDB->updateDocument($profile->getArrayCopy());
if(false === $profile) {
if (false === $profile) {
throw new Exception('Failed to save user to DB', 500);
}
@ -490,7 +480,7 @@ $utopia->post('/v1/auth/recovery')
$redirect['query'] = Template::mergeQuery(((isset($redirect['query'])) ? $redirect['query'] : ''), ['userId' => $profile->getUid(), 'token' => $secret]);
$redirect = Template::unParseURL($redirect);
$body = new Template(__DIR__ . '/../config/locale/templates/' . Locale::getText('auth.emails.recovery.body'));
$body = new Template(__DIR__.'/../config/locale/templates/'.Locale::getText('auth.emails.recovery.body'));
$body
->setParam('{{direction}}', Locale::getText('settings.direction'))
->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]']))
@ -503,13 +493,12 @@ $utopia->post('/v1/auth/recovery')
$mail->addAddress($profile->getAttribute('email', ''), $profile->getAttribute('name', ''));
$mail->Subject = Locale::getText('auth.emails.recovery.title');
$mail->Body = $body->render();
$mail->Body = $body->render();
$mail->AltBody = strip_tags($body->render());
try {
$mail->send();
}
catch(\Exception $error) {
} catch (\Exception $error) {
//throw new Exception('Problem sending mail: ' . $error->getError(), 500);
}
@ -535,9 +524,8 @@ $utopia->put('/v1/auth/recovery/reset')
->param('password-a', '', function () {return new Password();}, 'New password.')
->param('password-b', '', function () {return new Password();}, 'New password again.')
->action(
function($userId, $token, $passwordA, $passwordB) use ($response, $projectDB, $audit)
{
if($passwordA !== $passwordB) {
function ($userId, $token, $passwordA, $passwordB) use ($response, $projectDB, $audit) {
if ($passwordA !== $passwordB) {
throw new Exception('Passwords must match', 400);
}
@ -545,22 +533,22 @@ $utopia->put('/v1/auth/recovery/reset')
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'$uid=' . $userId
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'$uid='.$userId,
],
]);
if(empty($profile)) {
if (empty($profile)) {
throw new Exception('User not found', 404); // TODO maybe hide this
}
$token = Auth::tokenVerify($profile->getAttribute('tokens', []), Auth::TOKEN_TYPE_RECOVERY, $token);
if(!$token) {
if (!$token) {
throw new Exception('Recovery token is not valid', 401);
}
Authorization::setRole('user:' . $profile->getUid());
Authorization::setRole('user:'.$profile->getUid());
$profile = $projectDB->updateDocument(array_merge($profile->getArrayCopy(), [
'password' => Auth::passwordHash($passwordA),
@ -568,11 +556,11 @@ $utopia->put('/v1/auth/recovery/reset')
'confirm' => true,
]));
if(false === $profile) {
if (false === $profile) {
throw new Exception('Failed saving user to DB', 500);
}
if(!$projectDB->deleteDocument($token)) {
if (!$projectDB->deleteDocument($token)) {
throw new Exception('Failed to remove token from DB', 500);
}
@ -587,7 +575,7 @@ $utopia->put('/v1/auth/recovery/reset')
$utopia->get('/v1/auth/oauth/:provider')
->desc('OAuth Login')
->label('error', __DIR__ . '/../views/general/error.phtml')
->label('error', __DIR__.'/../views/general/error.phtml')
->label('scope', 'auth')
->label('sdk.namespace', 'auth')
->label('sdk.method', 'oauth')
@ -597,26 +585,25 @@ $utopia->get('/v1/auth/oauth/:provider')
->param('success', '', function () use ($clients) {return new Host($clients);}, 'URL to redirect back to your app after a successful login attempt.', true)
->param('failure', '', function () use ($clients) {return new Host($clients);}, 'URL to redirect back to your app after a failed login attempt.', true)
->action(
function($provider, $success, $failure) use ($response, $request, $project)
{
$callback = $request->getServer('REQUEST_SCHEME', 'https') . '://' . $request->getServer('HTTP_HOST') . '/v1/auth/oauth/callback/' . $provider . '/' . $project->getUid();
$appId = $project->getAttribute('usersOauth' . ucfirst($provider) . 'Appid', '');
$appSecret = $project->getAttribute('usersOauth' . ucfirst($provider) . 'Secret', '{}');
function ($provider, $success, $failure) use ($response, $request, $project) {
$callback = $request->getServer('REQUEST_SCHEME', 'https').'://'.$request->getServer('HTTP_HOST').'/v1/auth/oauth/callback/'.$provider.'/'.$project->getUid();
$appId = $project->getAttribute('usersOauth'.ucfirst($provider).'Appid', '');
$appSecret = $project->getAttribute('usersOauth'.ucfirst($provider).'Secret', '{}');
$appSecret = json_decode($appSecret, true);
$appSecret = json_decode($appSecret, true);
if(!empty($appSecret) && isset($appSecret['version'])) {
$key = $request->getServer('_APP_OPENSSL_KEY_V' . $appSecret['version']);
$appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key,0, hex2bin($appSecret['iv']), hex2bin($appSecret['tag']));
if (!empty($appSecret) && isset($appSecret['version'])) {
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$appSecret['version']);
$appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, hex2bin($appSecret['iv']), hex2bin($appSecret['tag']));
}
if(empty($appId) || empty($appSecret)) {
if (empty($appId) || empty($appSecret)) {
throw new Exception('Provider is undefined, configure provider app ID and app secret key to continue', 412);
}
$classname = 'Auth\\OAuth\\' . ucfirst($provider);
if(!class_exists($classname)) {
$classname = 'Auth\\OAuth\\'.ucfirst($provider);
if (!class_exists($classname)) {
throw new Exception('Provider is not supported', 501);
}
@ -628,7 +615,7 @@ $utopia->get('/v1/auth/oauth/:provider')
$utopia->get('/v1/auth/oauth/callback/:provider/:projectId')
->desc('OAuth Callback')
->label('error', __DIR__ . '/../views/general/error.phtml')
->label('error', __DIR__.'/../views/general/error.phtml')
->label('scope', 'auth')
->label('sdk.namespace', 'auth')
->label('sdk.method', 'oauthCallback')
@ -639,16 +626,15 @@ $utopia->get('/v1/auth/oauth/callback/:provider/:projectId')
->param('code', '', function () {return new Text(1024);}, 'OAuth code')
->param('state', '', function () {return new Text(2048);}, 'Login state params', true)
->action(
function($projectId, $provider, $code, $state) use ($response, $request, $domain)
{
$response->redirect($request->getServer('REQUEST_SCHEME', 'https') . '://' . $domain . '/v1/auth/oauth/' . $provider . '/redirect?'
. http_build_query(['project' => $projectId, 'code' => $code, 'state' => $state]));
function ($projectId, $provider, $code, $state) use ($response, $request, $domain) {
$response->redirect($request->getServer('REQUEST_SCHEME', 'https').'://'.$domain.'/v1/auth/oauth/'.$provider.'/redirect?'
.http_build_query(['project' => $projectId, 'code' => $code, 'state' => $state]));
}
);
$utopia->get('/v1/auth/oauth/:provider/redirect')
->desc('OAuth Redirect')
->label('error', __DIR__ . '/../views/general/error.phtml')
->label('error', __DIR__.'/../views/general/error.phtml')
->label('webhook', 'auth.oauth')
->label('scope', 'auth')
->label('sdk.namespace', 'auth')
@ -660,46 +646,42 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
->param('code', '', function () {return new Text(1024);}, 'OAuth code')
->param('state', '', function () {return new Text(2048);}, 'OAuth state params', true)
->action(
function($provider, $code, $state) use ($response, $request, $user, $projectDB, $project, $audit)
{
$callback = $request->getServer('REQUEST_SCHEME', 'https') . '://' . $request->getServer('HTTP_HOST') . '/v1/auth/oauth/callback/' . $provider . '/' . $project->getUid();
$defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => ''];
$validateURL = new URL();
function ($provider, $code, $state) use ($response, $request, $user, $projectDB, $project, $audit) {
$callback = $request->getServer('REQUEST_SCHEME', 'https').'://'.$request->getServer('HTTP_HOST').'/v1/auth/oauth/callback/'.$provider.'/'.$project->getUid();
$defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => ''];
$validateURL = new URL();
if(!empty($state)) {
if (!empty($state)) {
try {
$state = array_merge($defaultState, json_decode($state, true));
}
catch (\Exception $exception) {
} catch (\Exception $exception) {
throw new Exception('Failed to parse login state params as passed from OAuth provider');
}
}
else {
} else {
$state = $defaultState;
}
if(!$validateURL->isValid($state['success'])) {
if (!$validateURL->isValid($state['success'])) {
throw new Exception('Invalid redirect URL for success login', 400);
}
if(!empty($state['failure']) && !$validateURL->isValid($state['failure'])) {
if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) {
throw new Exception('Invalid redirect URL for failure login', 400);
}
$appId = $project->getAttribute('usersOauth' . ucfirst($provider) . 'Appid', '');
$appSecret = $project->getAttribute('usersOauth' . ucfirst($provider) . 'Secret', '{}');
$appId = $project->getAttribute('usersOauth'.ucfirst($provider).'Appid', '');
$appSecret = $project->getAttribute('usersOauth'.ucfirst($provider).'Secret', '{}');
$appSecret = json_decode($appSecret, true);
$appSecret = json_decode($appSecret, true);
if(!empty($appSecret) && isset($appSecret['version'])) {
$key = $request->getServer('_APP_OPENSSL_KEY_V' . $appSecret['version']);
$appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key,0, hex2bin($appSecret['iv']), hex2bin($appSecret['tag']));
if (!empty($appSecret) && isset($appSecret['version'])) {
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$appSecret['version']);
$appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, hex2bin($appSecret['iv']), hex2bin($appSecret['tag']));
}
$classname = 'Auth\\OAuth\\'.ucfirst($provider);
$classname = 'Auth\\OAuth\\' . ucfirst($provider);
if(!class_exists($classname)) {
if (!class_exists($classname)) {
throw new Exception('Provider is not supported', 501);
}
@ -707,8 +689,8 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
$accessToken = $oauth->getAccessToken($code);
if(empty($accessToken)) {
if(!empty($state['failure'])) {
if (empty($accessToken)) {
if (!empty($state['failure'])) {
$response->redirect($state['failure'], 301, 0);
}
@ -717,8 +699,8 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
$oauthID = $oauth->getUserID($accessToken);
if(empty($oauthID)) {
if(!empty($state['failure'])) {
if (empty($oauthID)) {
if (!empty($state['failure'])) {
$response->redirect($state['failure'], 301, 0);
}
@ -727,7 +709,7 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
$current = Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_LOGIN, Auth::$secret);
if($current) {
if ($current) {
$projectDB->deleteDocument($current); //throw new Exception('User already logged in', 401);
}
@ -735,25 +717,25 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'oauth' . ucfirst($provider) . '=' . $oauthID
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'oauth'.ucfirst($provider).'='.$oauthID,
],
]) : $user;
if(empty($user)) { // No user logged in or with oauth provider ID, create new one or connect with account with same email
$name = $oauth->getUserName($accessToken);
$email = $oauth->getUserEmail($accessToken);
if (empty($user)) { // No user logged in or with oauth provider ID, create new one or connect with account with same email
$name = $oauth->getUserName($accessToken);
$email = $oauth->getUserEmail($accessToken);
$user = $projectDB->getCollection([ // Get user by provider email address
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'email=' . $email
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'email='.$email,
],
]);
if(empty($user->getUid())) { // Last option -> create user alone, generate random password
if (empty($user->getUid())) { // Last option -> create user alone, generate random password
Authorization::disable();
$user = $projectDB->createDocument([
@ -771,7 +753,7 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
Authorization::enable();
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
}
@ -783,12 +765,12 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
$expiry = time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG;
$user
->setAttribute('oauth' . ucfirst($provider), $oauthID)
->setAttribute('oauth' . ucfirst($provider) . 'AccessToken', $accessToken)
->setAttribute('oauth'.ucfirst($provider), $oauthID)
->setAttribute('oauth'.ucfirst($provider).'AccessToken', $accessToken)
->setAttribute('status', Auth::USER_STATUS_ACTIVATED)
->setAttribute('tokens', new Document([
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:' . $user['$uid']], 'write' => ['user:' . $user['$uid']]],
'$permissions' => ['read' => ['user:'.$user['$uid']], 'write' => ['user:'.$user['$uid']]],
'type' => Auth::TOKEN_TYPE_LOGIN,
'secret' => Auth::hash($secret), // On way hash encryption to protect DB leak
'expire' => $expiry,
@ -797,11 +779,11 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
]), Document::SET_TYPE_APPEND)
;
Authorization::setRole('user:' . $user->getUid());
Authorization::setRole('user:'.$user->getUid());
$user = $projectDB->updateDocument($user->getArrayCopy());
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
@ -817,4 +799,4 @@ $utopia->get('/v1/auth/oauth/:provider/redirect')
$response->redirect($state['success']);
}
);
);

View file

@ -16,21 +16,20 @@ use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer;
$types = [
'browsers' => include __DIR__ . '/../config/avatars/browsers.php',
'credit-cards' => include __DIR__ . '/../config/avatars/credit-cards.php',
'flags' => include __DIR__ . '/../config/avatars/flags.php',
'browsers' => include __DIR__.'/../config/avatars/browsers.php',
'credit-cards' => include __DIR__.'/../config/avatars/credit-cards.php',
'flags' => include __DIR__.'/../config/avatars/flags.php',
];
$avatarCallback = function($type, $code, $width, $height, $quality) use ($types, $response, $request)
{
$avatarCallback = function ($type, $code, $width, $height, $quality) use ($types, $response, $request) {
$code = strtolower($code);
$type = strtolower($type);
if(!array_key_exists($type, $types)) {
if (!array_key_exists($type, $types)) {
throw new Exception('Avatar set not found', 404);
}
if(!array_key_exists($code, $types[$type])) {
if (!array_key_exists($code, $types[$type])) {
throw new Exception('Avatar not found', 404);
}
@ -38,20 +37,20 @@ $avatarCallback = function($type, $code, $width, $height, $quality) use ($types,
throw new Exception('Imagick extension is missing', 500);
}
$output = 'png';
$date = date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache
$key = md5('/v1/avatars/:type/:code-' . $code .$width . $height . $quality . $output);
$path = $types[$type][$code];
$type = 'png';
$output = 'png';
$date = date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
$key = md5('/v1/avatars/:type/:code-'.$code.$width.$height.$quality.$output);
$path = $types[$type][$code];
$type = 'png';
if (!file_exists($path)) {
throw new Exception('File not found in ' . $path, 404);
throw new Exception('File not found in '.$path, 404);
}
$cache = new Cache(new Filesystem('/storage/cache/app-0')); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
$cache = new Cache(new Filesystem('/storage/cache/app-0')); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
if($data) {
if ($data) {
//$output = (empty($output)) ? $type : $output;
$response
@ -64,7 +63,7 @@ $avatarCallback = function($type, $code, $width, $height, $quality) use ($types,
$resize = new Resize(file_get_contents($path));
$resize->crop((int)$width, (int)$height);
$resize->crop((int) $width, (int) $height);
$output = (empty($output)) ? $type : $output;
@ -88,7 +87,7 @@ $avatarCallback = function($type, $code, $width, $height, $quality) use ($types,
$utopia->get('/v1/avatars/credit-cards/:code')
->desc('Get Credit Card Icon')
->param('code', '', function () use ($types) {return new WhiteList(array_keys($types['credit-cards'])); }, 'Credit Card Code. Possible values: ' . implode(', ', array_keys($types['credit-cards'])) . '.')
->param('code', '', function () use ($types) {return new WhiteList(array_keys($types['credit-cards'])); }, 'Credit Card Code. Possible values: '.implode(', ', array_keys($types['credit-cards'])).'.')
->param('width', 100, function () {return new Range(0, 2000);}, 'Image width. Pass an integer between 0 to 2000. Defaults to 100', true)
->param('height', 100, function () {return new Range(0, 2000);}, 'Image height. Pass an integer between 0 to 2000. Defaults to 100', true)
->param('quality', 100, function () {return new Range(0, 100);}, 'Image quality. Pass an integer between 0 to 100. Defaults to 100', true)
@ -132,17 +131,16 @@ $utopia->get('/v1/avatars/image')
->label('sdk.method', 'getImage')
->label('sdk.description', 'Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in cases, you want to make sure a 3rd party image is properly served using a TLS protocol.')
->action(
function($url, $width, $height) use ($response, $request, $version)
{
$quality = 80;
$output = 'png';
$date = date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache
$key = md5('/v2/avatars/images-' . $url . '-' . $width . '/' . $height . '/' . $quality);
$type = 'png';
$cache = new Cache(new Filesystem('/storage/cache/app-0')); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 7 /* 1 week */);
function ($url, $width, $height) use ($response, $request, $version) {
$quality = 80;
$output = 'png';
$date = date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
$key = md5('/v2/avatars/images-'.$url.'-'.$width.'/'.$height.'/'.$quality);
$type = 'png';
$cache = new Cache(new Filesystem('/storage/cache/app-0')); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 7 /* 1 week */);
if($data) {
if ($data) {
$response
->setContentType('image/png')
->addHeader('Expires', $date)
@ -157,18 +155,17 @@ $utopia->get('/v1/avatars/image')
$fetch = @file_get_contents($url, false);
if(!$fetch) {
if (!$fetch) {
throw new Exception('Image not found', 404);
}
try {
$resize = new Resize($fetch);
}
catch (\Exception $exception) {
} catch (\Exception $exception) {
throw new Exception('Unable to parse image', 500);
}
$resize->crop((int)$width, (int)$height);
$resize->crop((int) $width, (int) $height);
$output = (empty($output)) ? $type : $output;
@ -199,19 +196,18 @@ $utopia->get('/v1/avatars/favicon')
->label('sdk.method', 'getFavicon')
->label('sdk.description', 'Use this endpoint to fetch the favorite icon (AKA favicon) of a any remote website URL.')
->action(
function($url) use ($response, $request, $version)
{
$width = 56;
$height = 56;
$quality = 80;
$output = 'png';
$date = date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache
$key = md5('/v2/avatars/favicon-' . $url);
$type = 'png';
$cache = new Cache(new Filesystem('/storage/cache/app-0')); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
function ($url) use ($response, $request, $version) {
$width = 56;
$height = 56;
$quality = 80;
$output = 'png';
$date = date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
$key = md5('/v2/avatars/favicon-'.$url);
$type = 'png';
$cache = new Cache(new Filesystem('/storage/cache/app-0')); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
if($data) {
if ($data) {
$response
->setContentType('image/png')
->addHeader('Expires', $date)
@ -234,11 +230,11 @@ $utopia->get('/v1/avatars/favicon')
CURLOPT_USERAGENT => sprintf(APP_USERAGENT, $version),
]);
$html = curl_exec($curl);
$html = curl_exec($curl);
curl_close($curl);
if(!$html) {
if (!$html) {
throw new Exception('Failed to fetch remote URL', 404);
}
@ -246,16 +242,16 @@ $utopia->get('/v1/avatars/favicon')
$doc->strictErrorChecking = false;
@$doc->loadHTML($html);
$links = $doc->getElementsByTagName('link');
$outputHref = '';
$outputExt = '';
$space = 0;
$links = $doc->getElementsByTagName('link');
$outputHref = '';
$outputExt = '';
$space = 0;
foreach ($links as $link) { /* @var $link DOMElement */
$href = $link->getAttribute('href');
$rel = $link->getAttribute('rel');
$sizes = $link->getAttribute('sizes');
$absolute = unparse_url(array_merge(parse_url($url), parse_url($href)));
$href = $link->getAttribute('href');
$rel = $link->getAttribute('rel');
$sizes = $link->getAttribute('sizes');
$absolute = unparse_url(array_merge(parse_url($url), parse_url($href)));
switch (strtolower($rel)) {
case 'icon':
@ -270,13 +266,13 @@ $utopia->get('/v1/avatars/favicon')
case 'jpeg':
$size = explode('x', strtolower($sizes));
$sizeWidth = (isset($size[0])) ? (int)$size[0] : 0;
$sizeHeight = (isset($size[1])) ? (int)$size[1] : 0;
$sizeWidth = (isset($size[0])) ? (int) $size[0] : 0;
$sizeHeight = (isset($size[1])) ? (int) $size[1] : 0;
if(($sizeWidth * $sizeHeight) >= $space) {
$space = $sizeWidth * $sizeHeight;
$outputHref = $absolute;
$outputExt = $ext;
if (($sizeWidth * $sizeHeight) >= $space) {
$space = $sizeWidth * $sizeHeight;
$outputHref = $absolute;
$outputExt = $ext;
}
break;
@ -286,17 +282,17 @@ $utopia->get('/v1/avatars/favicon')
}
}
if(empty($outputHref) || empty($outputExt)) {
if (empty($outputHref) || empty($outputExt)) {
$default = parse_url($url);
$outputHref = $default['scheme'] . '://' . $default['host'] . '/favicon.ico';
$outputHref = $default['scheme'].'://'.$default['host'].'/favicon.ico';
$outputExt = 'ico';
}
if('ico' == $outputExt) { // Skip crop, Imagick isn\'t supporting icon files
if ('ico' == $outputExt) { // Skip crop, Imagick isn\'t supporting icon files
$data = @file_get_contents($outputHref, false);
if(empty($data) || (mb_substr($data, 0, 5) === '<html') || mb_substr($data, 0, 5) === '<!doc') {
if (empty($data) || (mb_substr($data, 0, 5) === '<html') || mb_substr($data, 0, 5) === '<!doc') {
throw new Exception('Favicon not found', 404);
}
@ -312,13 +308,13 @@ $utopia->get('/v1/avatars/favicon')
$fetch = @file_get_contents($outputHref, false);
if(!$fetch) {
if (!$fetch) {
throw new Exception('Icon not found', 404);
}
$resize = new Resize($fetch);
$resize->crop((int)$width, (int)$height);
$resize->crop((int) $width, (int) $height);
$output = (empty($output)) ? $type : $output;
@ -352,8 +348,7 @@ $utopia->get('/v1/avatars/qr')
->label('sdk.method', 'getQR')
->label('sdk.description', 'Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.')
->action(
function($text, $size, $margin, $download) use ($response)
{
function ($text, $size, $margin, $download) use ($response) {
$renderer = new ImageRenderer(
new RendererStyle($size, $margin),
new ImagickImageBackEnd('png', 100)
@ -361,12 +356,12 @@ $utopia->get('/v1/avatars/qr')
$writer = new Writer($renderer);
if($download) {
if ($download) {
$response->addHeader('Content-Disposition', 'attachment; filename="qr.png"');
}
$response
->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
->setContentType('image/png')
->send('', $writer->writeString($text))
;
@ -374,43 +369,39 @@ $utopia->get('/v1/avatars/qr')
}
);
function unparse_url( $parsed_url , $ommit = array( ) )
function unparse_url($parsed_url, $ommit = array())
{
if(isset($parsed_url['path']) && mb_substr($parsed_url['path'], 0, 1) !== '/') {
$parsed_url['path'] = '/' . $parsed_url['path'];
if (isset($parsed_url['path']) && mb_substr($parsed_url['path'], 0, 1) !== '/') {
$parsed_url['path'] = '/'.$parsed_url['path'];
}
$p = array();
$p = array();
$p['scheme'] = isset( $parsed_url['scheme'] ) ? $parsed_url['scheme'] . '://' : '';
$p['scheme'] = isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://' : '';
$p['host'] = isset( $parsed_url['host'] ) ? $parsed_url['host'] : '';
$p['host'] = isset($parsed_url['host']) ? $parsed_url['host'] : '';
$p['port'] = isset( $parsed_url['port'] ) ? ':' . $parsed_url['port'] : '';
$p['port'] = isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
$p['user'] = isset( $parsed_url['user'] ) ? $parsed_url['user'] : '';
$p['user'] = isset($parsed_url['user']) ? $parsed_url['user'] : '';
$p['pass'] = isset( $parsed_url['pass'] ) ? ':' . $parsed_url['pass'] : '';
$p['pass'] = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
$p['pass'] = ( $p['user'] || $p['pass'] ) ? $p['pass']."@" : '';
$p['pass'] = ($p['user'] || $p['pass']) ? $p['pass'].'@' : '';
$p['path'] = isset( $parsed_url['path'] ) ? $parsed_url['path'] : '';
$p['path'] = isset($parsed_url['path']) ? $parsed_url['path'] : '';
$p['query'] = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : '';
$p['query'] = isset($parsed_url['query']) ? '?'.$parsed_url['query'] : '';
$p['fragment'] = isset( $parsed_url['fragment'] ) ? '#' . $parsed_url['fragment'] : '';
$p['fragment'] = isset($parsed_url['fragment']) ? '#'.$parsed_url['fragment'] : '';
if ( $ommit )
{
foreach ( $ommit as $key )
{
if ( isset( $p[ $key ] ) )
{
if ($ommit) {
foreach ($ommit as $key) {
if (isset($p[ $key ])) {
$p[ $key ] = '';
}
}
}
return $p['scheme'].$p['user'].$p['pass'].$p['host'].$p['port'].$p['path'].$p['query'].$p['fragment'];
}
}

View file

@ -1,4 +1,5 @@
<?php
include_once 'shared/web.php';
global $utopia, $response, $request, $layout, $version, $providers;
@ -14,14 +15,14 @@ $utopia->init(function () use ($layout, $utopia) {
;
});
$utopia->shutdown(function() use ($utopia, $response, $request, $layout, $version) {
$header = new View(__DIR__ . '/../views/console/comps/header.phtml');
$footer = new View(__DIR__ . '/../views/console/comps/footer.phtml');
$utopia->shutdown(function () use ($utopia, $response, $request, $layout, $version) {
$header = new View(__DIR__.'/../views/console/comps/header.phtml');
$footer = new View(__DIR__.'/../views/console/comps/footer.phtml');
$footer
->setParam('home', $request->getServer('_APP_HOME', ''))
;
$layout
->setParam('header', [$header])
->setParam('footer', [$footer])
@ -42,50 +43,47 @@ $utopia->get('/error/:code')
->label('permission', 'public')
->label('scope', 'home')
->param('code', null, new \Utopia\Validator\Numeric(), 'Valid status code number', false)
->action(function($code) use ($layout)
{
$page = new View(__DIR__ . '/../views/error.phtml');
->action(function ($code) use ($layout) {
$page = new View(__DIR__.'/../views/error.phtml');
$page
->setParam('code', $code)
;
$layout
->setParam('title', APP_NAME . ' - Error')
->setParam('title', APP_NAME.' - Error')
->setParam('body', $page);
});
$utopia->get('/console')
->label('permission', 'public')
->label('scope', 'console')
->action(function() use ($layout, $request)
{
$page = new View(__DIR__ . '/../views/console/index.phtml');
->action(function () use ($layout, $request) {
$page = new View(__DIR__.'/../views/console/index.phtml');
$page
->setParam('home', $request->getServer('_APP_HOME', ''))
;
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.title'))
->setParam('body', $page);
});
$utopia->get('/console/account')
->label('permission', 'public')
->label('scope', 'console')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/console/account/index.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/console/account/index.phtml');
$cc = new View(__DIR__ . '/../views/console/forms/credit-card.phtml');
$cc = new View(__DIR__.'/../views/console/forms/credit-card.phtml');
$page
->setParam('cc', $cc)
;
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.account.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.account.title'))
->setParam('body', $page);
});
@ -93,12 +91,11 @@ $utopia->get('/console/notifications')
->desc('Platform console notifications')
->label('permission', 'public')
->label('scope', 'console')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/v1/console/notifications/index.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/v1/console/notifications/index.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.notifications.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.notifications.title'))
->setParam('body', $page);
});
@ -106,12 +103,11 @@ $utopia->get('/console/home')
->desc('Platform console project home')
->label('permission', 'public')
->label('scope', 'console')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/console/home/index.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/console/home/index.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.home.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.home.title'))
->setParam('body', $page);
});
@ -120,10 +116,10 @@ $utopia->get('/console/settings')
->label('permission', 'public')
->label('scope', 'console')
->action(function () use ($layout) {
$page = new View(__DIR__ . '/../views/console/settings/index.phtml');
$page = new View(__DIR__.'/../views/console/settings/index.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.settings.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.settings.title'))
->setParam('body', $page);
});
@ -132,10 +128,10 @@ $utopia->get('/console/webhooks')
->label('permission', 'public')
->label('scope', 'console')
->action(function () use ($layout) {
$page = new View(__DIR__ . '/../views/console/webhooks/index.phtml');
$page = new View(__DIR__.'/../views/console/webhooks/index.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.webhooks.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.webhooks.title'))
->setParam('body', $page);
});
@ -144,10 +140,10 @@ $utopia->get('/console/keys')
->label('permission', 'public')
->label('scope', 'console')
->action(function () use ($layout) {
$page = new View(__DIR__ . '/../views/console/keys/index.phtml');
$page = new View(__DIR__.'/../views/console/keys/index.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.keys.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.keys.title'))
->setParam('body', $page);
});
@ -156,10 +152,10 @@ $utopia->get('/console/tasks')
->label('permission', 'public')
->label('scope', 'console')
->action(function () use ($layout) {
$page = new View(__DIR__ . '/../views/console/tasks/index.phtml');
$page = new View(__DIR__.'/../views/console/tasks/index.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.tasks.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.tasks.title'))
->setParam('body', $page);
});
@ -167,12 +163,11 @@ $utopia->get('/console/database')
->desc('Platform console project settings')
->label('permission', 'public')
->label('scope', 'console')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/console/database/index.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/console/database/index.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.database.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.database.title'))
->setParam('body', $page);
});
@ -181,22 +176,21 @@ $utopia->get('/console/database/collection')
->label('permission', 'public')
->label('scope', 'console')
->param('id', '', function () {return new UID();}, 'Collection unique ID.')
->action(function($id) use ($layout, $projectDB)
{
->action(function ($id) use ($layout, $projectDB) {
$collection = $projectDB->getDocument($id, false);
if(empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
if (empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
throw new Exception('Collection not found', 404);
}
$page = new View(__DIR__ . '/../views/console/database/collection.phtml');
$page = new View(__DIR__.'/../views/console/database/collection.phtml');
$page
->setParam('collection', $collection->getArrayCopy())
;
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.database.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.database.title'))
->setParam('body', $page);
});
@ -204,12 +198,11 @@ $utopia->get('/console/storage')
->desc('Platform console project settings')
->label('permission', 'public')
->label('scope', 'console')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/console/storage/index.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/console/storage/index.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.storage.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.storage.title'))
->setParam('body', $page);
});
@ -217,14 +210,13 @@ $utopia->get('/console/users')
->desc('Platform console project settings')
->label('permission', 'public')
->label('scope', 'console')
->action(function() use ($layout, $providers)
{
$page = new View(__DIR__ . '/../views/console/users/index.phtml');
->action(function () use ($layout, $providers) {
$page = new View(__DIR__.'/../views/console/users/index.phtml');
$page->setParam('providers', $providers);
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.users.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.users.title'))
->setParam('body', $page);
});
@ -232,11 +224,10 @@ $utopia->get('/console/users/view')
->desc('Platform console project user')
->label('permission', 'public')
->label('scope', 'console')
->action(function() use ($layout, $providers)
{
$page = new View(__DIR__ . '/../views/console/users/view.phtml');
->action(function () use ($layout, $providers) {
$page = new View(__DIR__.'/../views/console/users/view.phtml');
$layout
->setParam('title', APP_NAME . ' - ' . Locale::getText('console.users.title'))
->setParam('title', APP_NAME.' - '.Locale::getText('console.users.title'))
->setParam('body', $page);
});
});

View file

@ -25,8 +25,7 @@ $isDev = (App::ENV_TYPE_PRODUCTION !== $utopia->getEnv());
$utopia
->shutdown(
function() use ($request, $response, $projectDB, $register, &$output)
{
function () use ($request, $response, $projectDB, $register, &$output) {
/*$lastModified = $projectDB->lastModified();
$etag = md5(json_encode($output));
$ifNotModelledSince = strtotime($request->getServer('HTTP_IF_MODIFIED_SINCE', 'now'));
@ -64,11 +63,10 @@ $utopia->get('/v1/database')
->label('sdk.description', 'Get a list of all the user collections. You can use the query params to filter your results. On admin mode, this endpoint will return a list of all of the project collections. [Learn more about different API modes](/docs/modes).')
->param('search', '', function () {return new Text(256);}, 'Search term to filter your list results.', true)
->param('limit', 25, function () {return new Range(0, 100);}, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0 , function () {return new Range(0, 40000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('offset', 0, function () {return new Range(0, 40000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () {return new WhiteList(['ASC', 'DESC']);}, 'Order result by ASC or DESC order.', true)
->action(
function($search, $limit, $offset, $orderType) use ($response, $projectDB)
{
function ($search, $limit, $offset, $orderType) use ($response, $projectDB) {
/*$vl = new Structure($projectDB);
var_dump($vl->isValid(new Document([
@ -96,7 +94,7 @@ $utopia->get('/v1/database')
'orderCast' => 'string',
'search' => $search,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_COLLECTIONS
'$collection='.Database::SYSTEM_COLLECTION_COLLECTIONS,
],
]);
@ -112,10 +110,10 @@ $utopia->get('/v1/database/:collectionId')
->label('sdk.description', 'Get collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.')
->param('collectionId', '', function () {return new UID();}, 'Collection unique ID.')
->action(
function($collectionId) use ($response, $projectDB) {
function ($collectionId) use ($response, $projectDB) {
$collection = $projectDB->getDocument($collectionId, false);
if(empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
if (empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
throw new Exception('Collection not found', 404);
}
@ -135,14 +133,13 @@ $utopia->post('/v1/database')
->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of write permissions. [Learn more about permissions and roles](/docs/permissions).', true)
->param('rules', [], function () use ($projectDB) {return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES]));}, 'Array of collection structure rules. Each rule define a collection field name, data type and validation', true)
->action(
function($name, $read, $write, $rules) use ($response, $projectDB, &$output, $webhook, $audit, $isDev)
{
function ($name, $read, $write, $rules) use ($response, $projectDB, &$output, $webhook, $audit, $isDev) {
try {
$data = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
'name' => $name,
'dateCreated' => time(),
'dateUpdated' => time(),
'dateCreated' => time(),
'dateUpdated' => time(),
'structure' => true,
'$permissions' => [
'read' => $read,
@ -150,14 +147,11 @@ $utopia->post('/v1/database')
],
'rules' => $rules,
]);
}
catch (AuthorizationException $exception) {
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
}
catch (StructureException $exception) {
throw new Exception('Bad structure. ' . $exception->getMessage(), 400);
}
catch (\Exception $exception) {
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
throw new Exception('Failed saving document to DB', 500);
}
@ -169,11 +163,11 @@ $utopia->post('/v1/database')
$audit
->setParam('event', 'database.collections.create')
->setParam('resource', 'database/collection/' . $data['$uid'])
->setParam('resource', 'database/collection/'.$data['$uid'])
->setParam('data', $data)
;
/**
/*
* View
*/
$response
@ -195,11 +189,10 @@ $utopia->put('/v1/database/:collectionId')
->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of write permissions. [Learn more about permissions and roles](/docs/permissions).', true)
->param('rules', [], function () use ($projectDB) {return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES]));}, 'Array of collection structure rules. Each rule define a collection field name, data type and validation', true)
->action(
function($collectionId, $name, $read, $write, $rules) use ($response, $projectDB)
{
function ($collectionId, $name, $read, $write, $rules) use ($response, $projectDB) {
$collection = $projectDB->getDocument($collectionId, false);
if(empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
if (empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
throw new Exception('Collection not found', 404);
}
@ -214,7 +207,7 @@ $utopia->put('/v1/database/:collectionId')
'rules' => $rules,
]));
if(false === $collection) {
if (false === $collection) {
throw new Exception('Failed saving collection to DB', 500);
}
@ -230,20 +223,20 @@ $utopia->delete('/v1/database/:collectionId')
->label('sdk.description', 'Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.')
->param('collectionId', '', function () {return new UID();}, 'Collection unique ID.')
->action(
function($collectionId) use ($response, $projectDB, $audit) {
function ($collectionId) use ($response, $projectDB, $audit) {
$collection = $projectDB->getDocument($collectionId, false);
if(empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
if (empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
throw new Exception('Collection not found', 404);
}
if(!$projectDB->deleteDocument($collectionId)) {
if (!$projectDB->deleteDocument($collectionId)) {
throw new Exception('Failed to remove collection from DB', 500);
}
$audit
->setParam('event', 'database.collections.create')
->setParam('resource', 'database/collection/' . $collection->getUid())
->setParam('resource', 'database/collection/'.$collection->getUid())
->setParam('data', $collection->getArrayCopy()) // Audit document in case of malicious or disastrous action
;
@ -268,11 +261,10 @@ $utopia->get('/v1/database/:collectionId/documents')
->param('first', 0, function () {return new Range(0, 1);}, 'Return only first document. Pass 1 for true or 0 for false. The default value is 0.', true)
->param('last', 0, function () {return new Range(0, 1);}, 'Return only last document. Pass 1 for true or 0 for false. The default value is 0.', true)
->action(
function($collectionId, $filters, $offset, $limit, $orderField, $orderType, $orderCast, $search, $first, $last) use ($response, $request, $projectDB, &$output, $isDev)
{
function ($collectionId, $filters, $offset, $limit, $orderField, $orderType, $orderCast, $search, $first, $last) use ($response, $request, $projectDB, &$output, $isDev) {
$collection = $projectDB->getDocument($collectionId, $isDev);
if(is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
if (is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
throw new Exception('Collection not found', 404);
}
@ -283,18 +275,17 @@ $utopia->get('/v1/database/:collectionId/documents')
'orderType' => $orderType,
'orderCast' => $orderCast,
'search' => $search,
'first' => (bool)$first,
'last' => (bool)$last,
'first' => (bool) $first,
'last' => (bool) $last,
'filters' => array_merge($filters, [
'$collection=' . $collectionId
'$collection='.$collectionId,
]),
]);
if($first || $last) {
if ($first || $last) {
$response->json((!empty($list) ? $list->getArrayCopy() : []));
}
else {
if($isDev) {
} else {
if ($isDev) {
$collection
->setAttribute('debug', $projectDB->getDebug())
->setAttribute('limit', $limit)
@ -311,7 +302,7 @@ $utopia->get('/v1/database/:collectionId/documents')
->setAttribute('documents', $list)
;
/**
/*
* View
*/
$response->json($collection->getArrayCopy(/*['$uid', '$collection', 'name', 'documents']*/[], ['rules']));
@ -328,9 +319,8 @@ $utopia->get('/v1/database/:collectionId/documents/:documentId')
->param('collectionId', null, function () {return new UID();}, 'Collection unique ID')
->param('documentId', null, function () {return new UID();}, 'Document unique ID')
->action(
function($collectionId, $documentId) use ($response, $request, $projectDB, &$output, $isDev)
{
$document = $projectDB->getDocument($documentId, $isDev);
function ($collectionId, $documentId) use ($response, $request, $projectDB, &$output, $isDev) {
$document = $projectDB->getDocument($documentId, $isDev);
$collection = $projectDB->getDocument($collectionId, $isDev);
if (empty($document->getArrayCopy()) || $document->getCollection() != $collection->getUid()) { // Check empty
@ -341,25 +331,24 @@ $utopia->get('/v1/database/:collectionId/documents/:documentId')
$paths = explode('/', $request->getParam('q', ''));
$paths = array_slice($paths, 6, count($paths));
if(count($paths) > 0) {
if(count($paths) % 2 == 1) {
if (count($paths) > 0) {
if (count($paths) % 2 == 1) {
$output = $document->getAttribute(implode('.', $paths));
}
else {
$id = (int)array_pop($paths);
} else {
$id = (int) array_pop($paths);
$output = $document->search('$uid', $id, $document->getAttribute(implode('.', $paths)));
}
$output = ($output instanceof Document) ? $output->getArrayCopy() : $output;
var_dump($output);
if(!is_array($output)) {
if (!is_array($output)) {
throw new Exception('No document found', 404);
}
}
/**
/*
* View
*/
$response->json($output);
@ -381,19 +370,18 @@ $utopia->post('/v1/database/:collectionId/documents')
->param('parentProperty', '', function () {return new Key();}, 'Parent document property name. Use when you want your new document to be a child of a parent document.', true)
->param('parentPropertyType', Document::SET_TYPE_ASSIGN, function () {return new WhiteList([Document::SET_TYPE_ASSIGN, Document::SET_TYPE_APPEND, Document::SET_TYPE_PREPEND]);}, 'Parent document property connection type. You can set this value to **assign**, **append** or **prepend**, default value is assign. Use when you want your new document to be a child of a parent document.', true)
->action(
function($collectionId, $data, $read, $write, $parentDocument, $parentProperty, $parentPropertyType) use ($response, $projectDB, &$output, $webhook, $audit, $isDev)
{
if(empty($data)) {
function ($collectionId, $data, $read, $write, $parentDocument, $parentProperty, $parentPropertyType) use ($response, $projectDB, &$output, $webhook, $audit, $isDev) {
if (empty($data)) {
throw new Exception('Missing payload', 400);
}
if(isset($data['$uid'])) {
if (isset($data['$uid'])) {
throw new Exception('$uid is not allowed for creating new documents, try update instead', 400);
}
$collection = $projectDB->getDocument($collectionId/*, $isDev*/);
if(is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
if (is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
throw new Exception('Collection not found', 404);
}
@ -404,14 +392,14 @@ $utopia->post('/v1/database/:collectionId/documents')
// Read parent document + validate not 404 + validate read / write permission like patch method
// Add payload to parent document property
if((!empty($parentDocument)) && (!empty($parentProperty))) {
if ((!empty($parentDocument)) && (!empty($parentProperty))) {
$parentDocument = $projectDB->getDocument($parentDocument);
if (empty($parentDocument->getArrayCopy())) { // Check empty
throw new Exception('No parent document found', 404);
}
/**
/*
* 1. Check child has valid structure,
* 2. Check user have write permission for parent document
* 3. Assign parent data (including child) to $data
@ -422,13 +410,13 @@ $utopia->post('/v1/database/:collectionId/documents')
$structure = new Structure($projectDB);
if(!$structure->isValid($new)) {
throw new Exception('Invalid data structure: ' . $structure->getDescription(), 400);
if (!$structure->isValid($new)) {
throw new Exception('Invalid data structure: '.$structure->getDescription(), 400);
}
$authorization = new Authorization($parentDocument, 'write');
if(!$authorization->isValid($new->getPermissions())) {
if (!$authorization->isValid($new->getPermissions())) {
throw new Exception('Unauthorized action', 401);
}
@ -440,15 +428,12 @@ $utopia->post('/v1/database/:collectionId/documents')
try {
$data = $projectDB->createDocument($data);
}
catch (AuthorizationException $exception) {
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
}
catch (StructureException $exception) {
throw new Exception('Bad structure. ' . $exception->getMessage(), 400);
}
catch (\Exception $exception) {
throw new Exception('Failed saving document to DB' . $exception->getMessage(), 500);
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
throw new Exception('Failed saving document to DB'.$exception->getMessage(), 500);
}
$data = $data->getArrayCopy();
@ -459,11 +444,11 @@ $utopia->post('/v1/database/:collectionId/documents')
$audit
->setParam('event', 'database.documents.create')
->setParam('resource', 'database/document/' . $data['$uid'])
->setParam('resource', 'database/document/'.$data['$uid'])
->setParam('data', $data)
;
/**
/*
* View
*/
$response
@ -485,12 +470,11 @@ $utopia->patch('/v1/database/:collectionId/documents/:documentId')
->param('read', [], function () {return new ArrayList(new Text(64));}, 'An array of read permissions. [Learn more about permissions and roles](/docs/permissions).', true)
->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of write permissions. [Learn more about permissions and roles](/docs/permissions).', true)
->action(
function($collectionId, $documentId, $data, $read, $write) use ($response, $projectDB, &$output, $webhook, $audit, $isDev)
{
function ($collectionId, $documentId, $data, $read, $write) use ($response, $projectDB, &$output, $webhook, $audit, $isDev) {
$collection = $projectDB->getDocument($collectionId/*, $isDev*/);
$document = $projectDB->getDocument($documentId, $isDev);
$document = $projectDB->getDocument($documentId, $isDev);
if(is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
if (is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
throw new Exception('Collection not found', 404);
}
@ -500,32 +484,29 @@ $utopia->patch('/v1/database/:collectionId/documents/:documentId')
//TODO check merge read write permissions
if(!empty($read)) { // Overwrite permissions only when passed
if (!empty($read)) { // Overwrite permissions only when passed
$data['$permissions']['read'] = $read;
}
if(!empty($write)) { // Overwrite permissions only when passed
if (!empty($write)) { // Overwrite permissions only when passed
$data['$permissions']['write'] = $read;
}
$data = array_merge($document->getArrayCopy(), $data);
$data['$collection'] = $collection->getUid(); // Make sure user don't switch collectionID
$data['$uid'] = $document->getUid(); // Make sure user don't switch document unique ID
$data['$collection'] = $collection->getUid(); // Make sure user don't switch collectionID
$data['$uid'] = $document->getUid(); // Make sure user don't switch document unique ID
if(empty($data)) {
if (empty($data)) {
throw new Exception('Missing payload', 400);
}
try {
$data = $projectDB->updateDocument($data);
}
catch (AuthorizationException $exception) {
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
}
catch (StructureException $exception) {
throw new Exception('Bad structure. ' . $exception->getMessage(), 400);
}
catch (\Exception $exception) {
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
throw new Exception('Failed saving document to DB', 500);
}
@ -537,11 +518,11 @@ $utopia->patch('/v1/database/:collectionId/documents/:documentId')
$audit
->setParam('event', 'database.documents.patch')
->setParam('resource', 'database/document/' . $data['$uid'])
->setParam('resource', 'database/document/'.$data['$uid'])
->setParam('data', $data)
;
/**
/*
* View
*/
$response->json($data);
@ -557,38 +538,35 @@ $utopia->delete('/v1/database/:collectionId/documents/:documentId')
->param('collectionId', null, function () {return new UID();}, 'Collection unique ID')
->param('documentId', null, function () {return new UID();}, 'Document unique ID')
->action(
function($collectionId, $documentId) use ($response, $projectDB, $audit, $isDev) {
function ($collectionId, $documentId) use ($response, $projectDB, $audit, $isDev) {
$collection = $projectDB->getDocument($collectionId, $isDev);
$document = $projectDB->getDocument($documentId, $isDev);
$document = $projectDB->getDocument($documentId, $isDev);
if (empty($document->getArrayCopy()) || $document->getCollection() != $collectionId) { // Check empty
throw new Exception('No document found', 404);
}
if(is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
if (is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
throw new Exception('Collection not found', 404);
}
try {
$projectDB->deleteDocument($documentId);
}
catch (AuthorizationException $exception) {
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
}
catch (StructureException $exception) {
throw new Exception('Bad structure. ' . $exception->getMessage(), 400);
}
catch (\Exception $exception) {
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
throw new Exception('Failed to remove document from DB', 500);
}
$audit
->setParam('event', 'database.documents.delete')
->setParam('resource', 'database/document/' . $documentId)
->setParam('resource', 'database/document/'.$documentId)
->setParam('data', $document->getArrayCopy()) // Audit document in case of malicious or disastrous action
;
$response->noContent();
}
);
);

View file

@ -14,8 +14,7 @@ $utopia->get('/v1/health')
->label('sdk.method', 'getDB')
->label('docs', false)
->action(
function() use ($response, $register)
{
function () use ($response, $register) {
$response->json(array('OK'));
}
);
@ -27,8 +26,7 @@ $utopia->get('/v1/health/db')
->label('sdk.method', 'getDB')
->label('docs', false)
->action(
function() use ($response, $register)
{
function () use ($response, $register) {
$register->get('db'); /* @var $db PDO */
$response->json(array('OK'));
@ -42,8 +40,7 @@ $utopia->get('/v1/health/cache')
->label('sdk.method', 'getCache')
->label('docs', false)
->action(
function() use ($response, $register)
{
function () use ($response, $register) {
$register->get('cache'); /* @var $cache Predis\Client */
$response->json(array('OK'));
@ -57,9 +54,8 @@ $utopia->get('/v1/health/time')
->label('sdk.method', 'getTime')
->label('docs', false)
->action(
function() use ($response)
{
/**
function () use ($response) {
/*
* Code from: @see https://www.beliefmedia.com.au/query-ntp-time-server
*/
$host = 'time.google.com'; // https://developers.google.com/time/
@ -71,7 +67,7 @@ $utopia->get('/v1/health/time')
socket_connect($sock, $host, 123);
/* Send request */
$msg = "\010" . str_repeat("\0", 47);
$msg = "\010".str_repeat("\0", 47);
socket_send($sock, $msg, strlen($msg), 0);
@ -89,7 +85,7 @@ $utopia->get('/v1/health/time')
$diff = ($timestamp - time());
if($diff > $gap || $diff < ($gap * -1)) {
if ($diff > $gap || $diff < ($gap * -1)) {
throw new Exception('Server time gaps detected');
}
@ -104,8 +100,7 @@ $utopia->get('/v1/health/webhooks')
->label('sdk.method', 'getWebhooks')
->label('docs', false)
->action(
function() use ($response)
{
function () use ($response) {
$response->json(['size' => Resque::size('webhooks')]);
}
);
@ -117,15 +112,14 @@ $utopia->get('/v1/health/storage/local')
->label('sdk.method', 'getStorageLocal')
->label('docs', false)
->action(
function() use ($response)
{
function () use ($response) {
$device = new Local();
if(!is_readable($device->getRoot())) {
if (!is_readable($device->getRoot())) {
throw new Exception('Device is not readable');
}
if(!is_writable($device->getRoot())) {
if (!is_writable($device->getRoot())) {
throw new Exception('Device is not writable');
}
@ -140,8 +134,7 @@ $utopia->get('/v1/health/storage/anti-virus')
->label('sdk.method', 'getStorageAntiVirus')
->label('docs', false)
->action(
function() use ($response)
{
function () use ($response) {
$antiVirus = new Network('clamav', 3310);
$response->json([
@ -158,10 +151,9 @@ $utopia->get('/v1/health/stats')
->label('sdk.method', 'getStats')
->label('docs', false)
->action(
function() use ($request, $response, $register, $project)
{
function () use ($request, $response, $register, $project) {
$device = Storage::getDevice('local');
$cache = $register->get('cache');
$cache = $register->get('cache');
$cacheStats = $cache->info();
@ -172,9 +164,9 @@ $utopia->get('/v1/health/stats')
'version' => shell_exec('nginx -v 2>&1'),
],
'storage' => [
'used' => $device->human($device->getDirectorySize($device->getRoot() . '/')),
'partitionTotal' => $device->human($device->getPartitionTotalSpace()),
'partitionFree' => $device->human($device->getPartitionFreeSpace()),
'used' => $device->human($device->getDirectorySize($device->getRoot().'/')),
'partitionTotal' => $device->human($device->getPartitionTotalSpace()),
'partitionFree' => $device->human($device->getPartitionFreeSpace()),
],
'cache' => [
'uptime' => (isset($cacheStats['uptime_in_seconds'])) ? $cacheStats['uptime_in_seconds'] : 0,
@ -185,7 +177,7 @@ $utopia->get('/v1/health/stats')
'memory_used_human' => (isset($cacheStats['used_memory_human'])) ? $cacheStats['used_memory_human'] : 0,
'memory_used_peak' => (isset($cacheStats['used_memory_peak'])) ? $cacheStats['used_memory_peak'] : 0,
'memory_used_peak_human' => (isset($cacheStats['used_memory_peak_human'])) ? $cacheStats['used_memory_peak_human'] : 0,
]
],
]);
}
);
);

View file

@ -11,10 +11,10 @@ $layout
->setParam('title', APP_NAME)
->setParam('description', Locale::getText('general.description'))
->setParam('class', 'home')
->setParam('header', [new View(__DIR__ . '/../views/home/comps/header.phtml')])
->setParam('header', [new View(__DIR__.'/../views/home/comps/header.phtml')])
;
$utopia->shutdown(function() use ($utopia, $response, $request, $layout, $version, $env) {
$utopia->shutdown(function () use ($utopia, $response, $request, $layout, $version, $env) {
$response->send($layout->render());
});
@ -22,8 +22,7 @@ $utopia->get('/')
->label('permission', 'public')
->label('scope', 'home')
->action(
function() use ($response)
{
function () use ($response) {
$response->redirect('/auth/signin');
}
);
@ -32,12 +31,11 @@ $utopia->get('/auth/signin')
->desc('Login page')
->label('permission', 'public')
->label('scope', 'home')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/home/auth/signin.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/home/auth/signin.phtml');
$layout
->setParam('title', Locale::getText('home.auth.signin.title') . ' - ' . APP_NAME)
->setParam('title', Locale::getText('home.auth.signin.title').' - '.APP_NAME)
->setParam('body', $page);
});
@ -45,12 +43,11 @@ $utopia->get('/auth/signup')
->desc('Registration page')
->label('permission', 'public')
->label('scope', 'home')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/home/auth/signup.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/home/auth/signup.phtml');
$layout
->setParam('title', Locale::getText('home.auth.signup.title') . ' - ' . APP_NAME)
->setParam('title', Locale::getText('home.auth.signup.title').' - '.APP_NAME)
->setParam('body', $page);
});
@ -58,12 +55,11 @@ $utopia->get('/auth/recovery')
->desc('Password recovery page')
->label('permission', 'public')
->label('scope', 'home')
->action(function() use ($request, $layout)
{
$page = new View(__DIR__ . '/../views/home/auth/recovery.phtml');
->action(function () use ($request, $layout) {
$page = new View(__DIR__.'/../views/home/auth/recovery.phtml');
$layout
->setParam('title', Locale::getText('home.auth.recovery.title') . ' - ' . APP_NAME)
->setParam('title', Locale::getText('home.auth.recovery.title').' - '.APP_NAME)
->setParam('body', $page);
});
@ -71,12 +67,11 @@ $utopia->get('/auth/confirm')
->desc('Account confirmation page')
->label('permission', 'public')
->label('scope', 'home')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/home/auth/confirm.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/home/auth/confirm.phtml');
$layout
->setParam('title', Locale::getText('home.auth.confirm.title') . ' - ' . APP_NAME)
->setParam('title', Locale::getText('home.auth.confirm.title').' - '.APP_NAME)
->setParam('body', $page);
});
@ -84,12 +79,11 @@ $utopia->get('/auth/join')
->desc('Account team join page')
->label('permission', 'public')
->label('scope', 'home')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/home/auth/join.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/home/auth/join.phtml');
$layout
->setParam('title', Locale::getText('home.auth.join.title') . ' - ' . APP_NAME)
->setParam('title', Locale::getText('home.auth.join.title').' - '.APP_NAME)
->setParam('body', $page);
});
@ -97,12 +91,11 @@ $utopia->get('/auth/recovery/reset')
->desc('Password recovery page')
->label('permission', 'public')
->label('scope', 'home')
->action(function() use ($layout)
{
$page = new View(__DIR__ . '/../views/home/auth/recovery/reset.phtml');
->action(function () use ($layout) {
$page = new View(__DIR__.'/../views/home/auth/recovery/reset.phtml');
$layout
->setParam('title', Locale::getText('home.auth.reset.title') . ' - ' . APP_NAME)
->setParam('title', Locale::getText('home.auth.reset.title').' - '.APP_NAME)
->setParam('body', $page);
});
@ -111,15 +104,14 @@ $utopia->get('/error/:code')
->label('permission', 'public')
->label('scope', 'home')
->param('code', null, new \Utopia\Validator\Numeric(), 'Valid status code number', false)
->action(function($code) use ($layout)
{
$page = new View(__DIR__ . '/../views/error.phtml');
->action(function ($code) use ($layout) {
$page = new View(__DIR__.'/../views/error.phtml');
$page
->setParam('code', $code)
;
$layout
->setParam('title', 'Error' . ' - ' . APP_NAME)
->setParam('title', 'Error'.' - '.APP_NAME)
->setParam('body', $page);
});
});

View file

@ -13,19 +13,18 @@ $utopia->get('/v1/locale')
->label('sdk.method', 'getLocale')
->label('sdk.description', 'Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in supported language.')
->action(
function() use ($response, $request, $utopia)
{
$eu = include __DIR__ . '/../config/eu.php';
$currencies = include __DIR__ . '/../config/currencies.php';
$reader = new Reader(__DIR__ . '/../db/GeoLite2/GeoLite2-Country.mmdb');
$output = [];
$ip = $request->getIP();
$time = (60 * 60 * 24 * 45); // 45 days cache
$countries = Locale::getText('countries');
function () use ($response, $request, $utopia) {
$eu = include __DIR__.'/../config/eu.php';
$currencies = include __DIR__.'/../config/currencies.php';
$reader = new Reader(__DIR__.'/../db/GeoLite2/GeoLite2-Country.mmdb');
$output = [];
$ip = $request->getIP();
$time = (60 * 60 * 24 * 45); // 45 days cache
$countries = Locale::getText('countries');
$continents = Locale::getText('continents');
if(App::ENV_TYPE_PRODUCTION !== $utopia->getEnv()) {
$ip = '79.177.241.94';
if (App::ENV_TYPE_PRODUCTION !== $utopia->getEnv()) {
$ip = '79.177.241.94';
}
$output['ip'] = $ip;
@ -42,14 +41,13 @@ $utopia->get('/v1/locale')
$output['eu'] = (in_array($record->country->isoCode, $eu)) ? true : false;
foreach ($currencies as $code => $element) {
if(isset($element['locations']) && isset($element['code']) && in_array($record->country->isoCode, $element['locations'])) {
if (isset($element['locations']) && isset($element['code']) && in_array($record->country->isoCode, $element['locations'])) {
$currency = $element['code'];
}
}
$output['currency'] = $currency;
}
catch(\Exception $e) {
} catch (\Exception $e) {
$output['countryCode'] = '--';
$output['country'] = Locale::getText('locale.country.unknown');
$output['continent'] = Locale::getText('locale.country.unknown');
@ -59,8 +57,8 @@ $utopia->get('/v1/locale')
}
$response
->addHeader('Cache-Control', 'public, max-age=' . $time)
->addHeader('Expires', date('D, d M Y H:i:s', time() + $time) . ' GMT') // 45 days cache
->addHeader('Cache-Control', 'public, max-age='.$time)
->addHeader('Expires', date('D, d M Y H:i:s', time() + $time).' GMT') // 45 days cache
->json($output);
}
);
@ -72,8 +70,7 @@ $utopia->get('/v1/locale/countries')
->label('sdk.method', 'getCountries')
->label('sdk.description', 'List of all countries. You can use the locale header to get the data in supported language.')
->action(
function() use ($response, $request)
{
function () use ($response, $request) {
$list = Locale::getText('countries'); /* @var $list array */
asort($list);
@ -89,14 +86,13 @@ $utopia->get('/v1/locale/countries/eu')
->label('sdk.method', 'getCountriesEU')
->label('sdk.description', 'List of all countries that are currently members of the EU. You can use the locale header to get the data in supported language. UK brexit date is currently set to 2019-10-31 and will be updated if and when needed.')
->action(
function() use ($response)
{
$countries = Locale::getText('countries'); /* @var $countries array */
$eu = include __DIR__ . '/../config/eu.php';
$list = [];
function () use ($response) {
$countries = Locale::getText('countries'); /* @var $countries array */
$eu = include __DIR__.'/../config/eu.php';
$list = [];
foreach ($eu as $code) {
if(array_key_exists($code, $countries)) {
if (array_key_exists($code, $countries)) {
$list[$code] = $countries[$code];
}
}
@ -114,15 +110,14 @@ $utopia->get('/v1/locale/countries/phones')
->label('sdk.method', 'getCountriesPhones')
->label('sdk.description', 'List of all countries phone codes. You can use the locale header to get the data in supported language.')
->action(
function() use ($response)
{
$list = include __DIR__ . '/../config/phones.php'; /* @var $list array */
function () use ($response) {
$list = include __DIR__.'/../config/phones.php'; /* @var $list array */
$countries = Locale::getText('countries'); /* @var $countries array */
$countries = Locale::getText('countries'); /* @var $countries array */
foreach ($list as $code => $name) {
if(array_key_exists($code, $countries)) {
$list[$code] = $countries[$code] . ' +' . $list[$code];
if (array_key_exists($code, $countries)) {
$list[$code] = $countries[$code].' +'.$list[$code];
}
}
@ -139,10 +134,9 @@ $utopia->get('/v1/locale/currencies')
->label('sdk.method', 'getCurrencies')
->label('sdk.description', 'List of all currencies, including currency symol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in supported language.')
->action(
function() use ($response)
{
$currencies = include __DIR__ . '/../config/currencies.php';
function () use ($response) {
$currencies = include __DIR__.'/../config/currencies.php';
$response->json($currencies);
}
);
);

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
<?php
/**
/*
* Created by PhpStorm.
* User: eldadfux
* Date: 11/10/2018
* Time: 18:30
*/
*/

View file

@ -11,11 +11,11 @@ $roles = [
['type' => 'admin', 'label' => Locale::getText('general.roles.admin')],
];
$layout = new View(__DIR__ . '/../../views/layouts/default.phtml');
$layout = new View(__DIR__.'/../../views/layouts/default.phtml');
/* AJAX check */
if(!empty($request->getQuery('version', ''))) {
$layout->setPath(__DIR__ . '/../../views/layouts/empty.phtml');
if (!empty($request->getQuery('version', ''))) {
$layout->setPath(__DIR__.'/../../views/layouts/empty.phtml');
}
$layout
@ -32,13 +32,13 @@ $layout
->setParam('env', $utopia->getEnv())
;
$utopia->shutdown(function() use ($utopia, $response, $request, $layout, $version, $env) {
$utopia->shutdown(function () use ($utopia, $response, $request, $layout, $version, $env) {
$time = (60 * 60 * 24 * 45); // 45 days cache
$isDev = (\Utopia\App::ENV_TYPE_DEVELOPMENT == $env);
$response
->addHeader('Cache-Control', 'public, max-age=' . $time)
->addHeader('Expires', date('D, d M Y H:i:s', time() + $time) . ' GMT') // 45 days cache
->addHeader('Cache-Control', 'public, max-age='.$time)
->addHeader('Expires', date('D, d M Y H:i:s', time() + $time).' GMT') // 45 days cache
->addHeader('X-UA-Compatible', 'IE=Edge'); // Deny IE browsers from going into quirks mode
$route = $utopia->match($request);
@ -48,4 +48,4 @@ $utopia->shutdown(function() use ($utopia, $response, $request, $layout, $versio
->setParam('isDev', $isDev)
->setParam('class', $scope)
;
});
});

View file

@ -22,7 +22,7 @@ use Storage\Compression\Algorithms\GZIP;
use Resize\Resize;
use OpenSSL\OpenSSL;
Storage::addDevice('local', new Local('app-' . $project->getUid()));
Storage::addDevice('local', new Local('app-'.$project->getUid()));
$fileLogos = [ // Based on this list @see http://stackoverflow.com/a/4212908/2299554
'default' => 'default.gif',
@ -60,18 +60,18 @@ $fileLogos = [ // Based on this list @see http://stackoverflow.com/a/4212908/229
];
$inputs = [
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
];
$outputs = [
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'webp' => 'image/webp',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'webp' => 'image/webp',
];
$mimes = [
@ -121,11 +121,10 @@ $utopia->get('/v1/storage/files')
->label('sdk.description', 'Get a list of all the user files. You can use the query params to filter your results. On admin mode, this endpoint will return a list of all of the project files. [Learn more about different API modes](/docs/modes).')
->param('search', '', function () {return new Text(256);}, 'Search term to filter your list results.', true)
->param('limit', 25, function () {return new Range(0, 100);}, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0 , function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('offset', 0, function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () {return new WhiteList(['ASC', 'DESC']);}, 'Order result by ASC or DESC order.', true)
->action(
function($search, $limit, $offset, $orderType) use ($response, $projectDB)
{
function ($search, $limit, $offset, $orderType) use ($response, $projectDB) {
$results = $projectDB->getCollection([
'limit' => $limit,
'offset' => $offset,
@ -134,7 +133,7 @@ $utopia->get('/v1/storage/files')
'orderCast' => 'int',
'search' => $search,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_FILES
'$collection='.Database::SYSTEM_COLLECTION_FILES,
],
]);
@ -154,10 +153,10 @@ $utopia->get('/v1/storage/files/:fileId')
->label('sdk.description', 'Get file by its unique ID. This endpoint response returns a JSON object with the file metadata.')
->param('fileId', '', function () {return new UID();}, 'File unique ID.')
->action(
function($fileId) use ($response, $projectDB) {
function ($fileId) use ($response, $projectDB) {
$file = $projectDB->getDocument($fileId);
if(empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
@ -180,48 +179,47 @@ $utopia->get('/v1/storage/files/:fileId/preview')
//->param('storage', 'local', function () {return new WhiteList(array('local'));}, 'Selected storage device. defaults to local')
//->param('token', '', function () {return new Text(128);}, 'Preview token', true)
->action(
function($fileId, $width, $height, $quality, $background, $output) use ($request, $response, $projectDB, $project, $inputs, $outputs, $fileLogos)
{
function ($fileId, $width, $height, $quality, $background, $output) use ($request, $response, $projectDB, $project, $inputs, $outputs, $fileLogos) {
$storage = 'local';
if (!extension_loaded('imagick')) {
throw new Exception('Imagick extension is missing', 500);
}
if(!Storage::exists($storage)) {
if (!Storage::exists($storage)) {
throw new Exception('No such storage device');
}
if((strpos($request->getServer('HTTP_ACCEPT'), 'image/webp') === false) && ('webp' == $output)) { // Fallback webp to jpeg when no browser support
if ((strpos($request->getServer('HTTP_ACCEPT'), 'image/webp') === false) && ('webp' == $output)) { // Fallback webp to jpeg when no browser support
$output = 'jpg';
}
$date = date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache
$key = md5($fileId . $width . $height . $quality . $background . $storage . $output);
$date = date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
$key = md5($fileId.$width.$height.$quality.$background.$storage.$output);
$file = $projectDB->getDocument($fileId);
$file = $projectDB->getDocument($fileId);
if(empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
$path = $file->getAttribute('path');
$algorithm = $file->getAttribute('algorithm');
$type = strtolower(pathinfo($path, PATHINFO_EXTENSION));
$cipher = $file->getAttribute('fileOpenSSLCipher');
$path = $file->getAttribute('path');
$algorithm = $file->getAttribute('algorithm');
$type = strtolower(pathinfo($path, PATHINFO_EXTENSION));
$cipher = $file->getAttribute('fileOpenSSLCipher');
//$mimeType = $file->getAttribute('mimeType', 'unknown');
$compressor = new GZIP();
$device = Storage::getDevice('local');
$compressor = new GZIP();
$device = Storage::getDevice('local');
if (!file_exists($path)) {
throw new Exception('File not found in ' . $path, 404);
throw new Exception('File not found in '.$path, 404);
}
$cache = new Cache(new Filesystem('/storage/cache/app-' . $project->getUid())); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
$cache = new Cache(new Filesystem('/storage/cache/app-'.$project->getUid())); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
if($data) {
if ($data) {
$output = (empty($output)) ? $type : $output;
$response
@ -234,27 +232,27 @@ $utopia->get('/v1/storage/files/:fileId/preview')
$source = $device->read($path);
if(!empty($cipher)) { // Decrypt
if (!empty($cipher)) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
$request->getServer('_APP_OPENSSL_KEY_V' . $file->getAttribute('fileOpenSSLVersion')),
$request->getServer('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
0,
hex2bin($file->getAttribute('fileOpenSSLIV')),
hex2bin($file->getAttribute('fileOpenSSLTag'))
);
}
if(!empty($algorithm)) {
if (!empty($algorithm)) {
$source = $compressor->decompress($source);
}
$resize = new Resize($source);
$resize->crop((int)$width, (int)$height);
$resize->crop((int) $width, (int) $height);
if(!empty($background)) {
$resize->setBackground('#' . $background);
if (!empty($background)) {
$resize->setBackground('#'.$background);
}
$output = (empty($output)) ? $type : $output;
@ -286,30 +284,29 @@ $utopia->get('/v1/storage/files/:fileId/download')
->label('sdk.description', 'Get file content by its unique ID. The endpoint response return with a \'Content-Disposition: attachment\' header that tells the browser to start downloading the file to user downloads directory.')
->param('fileId', '', function () {return new UID();}, 'File unique ID.')
->action(
function($fileId) use ($response, $request, $projectDB)
{
function ($fileId) use ($response, $request, $projectDB) {
$file = $projectDB->getDocument($fileId);
if(empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
$path = $file->getAttribute('path', '');
if (!file_exists($path)) {
throw new Exception('File not found in ' . $path, 404);
throw new Exception('File not found in '.$path, 404);
}
$compressor = new GZIP();
$device = Storage::getDevice('local');
$device = Storage::getDevice('local');
$source = $device->read($path);
if(!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
$request->getServer('_APP_OPENSSL_KEY_V' . $file->getAttribute('fileOpenSSLVersion')),
$request->getServer('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
0,
hex2bin($file->getAttribute('fileOpenSSLIV')),
hex2bin($file->getAttribute('fileOpenSSLTag'))
@ -321,8 +318,8 @@ $utopia->get('/v1/storage/files/:fileId/download')
// Response
$response
->setContentType($file->getAttribute('mimeType'))
->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"')
->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
->addHeader('Content-Disposition', 'attachment; filename="'.$file->getAttribute('name', '').'"')
->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
->addHeader('X-Peak', memory_get_peak_usage())
->send($source)
;
@ -338,48 +335,47 @@ $utopia->get('/v1/storage/files/:fileId/view')
->param('fileId', '', function () {return new UID();}, 'File unique ID.')
->param('as', '', function () {return new WhiteList(['pdf', /*'html',*/ 'text']);}, 'Choose a file format to convert your file to. Currently you can only convert word and pdf files to pdf or txt. This option is currently experimental only, use at your own risk.', true)
->action(
function($fileId, $as) use ($response, $request, $projectDB, $mimes)
{
function ($fileId, $as) use ($response, $request, $projectDB, $mimes) {
$file = $projectDB->getDocument($fileId);
if(empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
$path = $file->getAttribute('path', '');
if (!file_exists($path)) {
throw new Exception('File not found in ' . $path, 404);
throw new Exception('File not found in '.$path, 404);
}
$compressor = new GZIP();
$device = Storage::getDevice('local');
$compressor = new GZIP();
$device = Storage::getDevice('local');
$contentType = 'text/plain';
if(in_array($file->getAttribute('mimeType'), $mimes)) {
if (in_array($file->getAttribute('mimeType'), $mimes)) {
$contentType = $file->getAttribute('mimeType');
}
$source = $device->read($path);
if(!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
$request->getServer('_APP_OPENSSL_KEY_V' . $file->getAttribute('fileOpenSSLVersion')),
$request->getServer('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
0,
hex2bin($file->getAttribute('fileOpenSSLIV')),
hex2bin($file->getAttribute('fileOpenSSLTag'))
);
}
$output = $compressor->decompress($source);
$fileName = $file->getAttribute('name', '');
$output = $compressor->decompress($source);
$fileName = $file->getAttribute('name', '');
$contentTypes = [
'pdf' => 'application/pdf',
'text' => 'text/plain',
'pdf' => 'application/pdf',
'text' => 'text/plain',
];
$contentType = (array_key_exists($as, $contentTypes)) ? $contentTypes[$as] : $contentType;
@ -389,8 +385,8 @@ $utopia->get('/v1/storage/files/:fileId/view')
->setContentType($contentType)
->addHeader('Content-Security-Policy', 'script-src none;')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Content-Disposition', 'inline; filename="' . $fileName . '"')
->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
->addHeader('Content-Disposition', 'inline; filename="'.$fileName.'"')
->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
->addHeader('X-Peak', memory_get_peak_usage())
->send($output)
;
@ -409,26 +405,25 @@ $utopia->post('/v1/storage/files')
->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of write permissions. [Learn more about permissions and roles](/docs/permissions).', true)
->param('folderId', '', function () {return new UID();}, 'Folder to associate files with.', true)
->action(
function($files, $read, $write, $folderId) use ($request, $response, $user, $projectDB, $audit, $usage)
{
$files = $request->getFiles('files');
$read = (empty($read)) ? ['user:' . $user->getUid()] : $read;
$write = (empty($write)) ? ['user:' . $user->getUid()] : $write;
function ($files, $read, $write, $folderId) use ($request, $response, $user, $projectDB, $audit, $usage) {
$files = $request->getFiles('files');
$read = (empty($read)) ? ['user:'.$user->getUid()] : $read;
$write = (empty($write)) ? ['user:'.$user->getUid()] : $write;
/**
/*
* Validation
*/
//$fileType = new FileType(array(FileType::FILE_TYPE_PNG, FileType::FILE_TYPE_GIF, FileType::FILE_TYPE_JPEG));
$fileSize = new FileSize(2097152 * 2); // 4MB
$fileSize = new FileSize(2097152 * 2); // 4MB
if (empty($files)) {
throw new Exception('No files sent', 400);
}
// Make sure we handle single file and multiple files the same way
$files['name'] = (is_array($files['name'])) ? $files['name'] : [$files['name']];
$files['tmp_name'] = (is_array($files['tmp_name'])) ? $files['tmp_name'] : [$files['tmp_name']];
$files['size'] = (is_array($files['size'])) ? $files['size'] : [$files['size']];
$files['name'] = (is_array($files['name'])) ? $files['name'] : [$files['name']];
$files['tmp_name'] = (is_array($files['tmp_name'])) ? $files['tmp_name'] : [$files['tmp_name']];
$files['size'] = (is_array($files['size'])) ? $files['size'] : [$files['size']];
// Check if file type is allowed
//foreach ($files['tmp_name'] as $tmpName) {
@ -446,18 +441,18 @@ $utopia->post('/v1/storage/files')
$antiVirus = new Network('clamav', 3310);
/**
/*
* Models
*/
$list = [];
$list = [];
$device = Storage::getDevice('local');
foreach ($files['tmp_name'] as $i => $tmpName) {
// Save to storage
$name = $files['name'][$i];
$size = $device->getFileSize($tmpName);
$path = $device->upload($tmpName, $files['name'][$i]);
$mimeType = $device->getFileMimeType($path);
$name = $files['name'][$i];
$size = $device->getFileSize($tmpName);
$path = $device->upload($tmpName, $files['name'][$i]);
$mimeType = $device->getFileMimeType($path);
// Check if file size is exceeding allowed limit
if (!$antiVirus->fileScan($path)) {
@ -466,45 +461,45 @@ $utopia->post('/v1/storage/files')
}
// Compression
$compressor = new GZIP();
$data = $device->read($path);
$data = $compressor->compress($data);
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
$compressor = new GZIP();
$data = $device->read($path);
$data = $compressor->compress($data);
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
$sizeCompressed = (int)$device->write($path, $data);
$sizeCompressed = (int) $device->write($path, $data);
$file = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_FILES,
'$permissions' => [
'$collection' => Database::SYSTEM_COLLECTION_FILES,
'$permissions' => [
'read' => $read,
'write' => $write,
],
'dateCreated' => time(),
'folderId' => $folderId,
'name' => $name,
'path' => $path,
'signature' => $device->getFileHash($path),
'mimeType' => $mimeType,
'sizeOriginal' => $size,
'sizeCompressed' => $sizeCompressed,
'algorithm' => $compressor->getName(),
'token' => bin2hex(random_bytes(64)),
'comment' => '',
'fileOpenSSLVersion'=> '1',
'dateCreated' => time(),
'folderId' => $folderId,
'name' => $name,
'path' => $path,
'signature' => $device->getFileHash($path),
'mimeType' => $mimeType,
'sizeOriginal' => $size,
'sizeCompressed' => $sizeCompressed,
'algorithm' => $compressor->getName(),
'token' => bin2hex(random_bytes(64)),
'comment' => '',
'fileOpenSSLVersion' => '1',
'fileOpenSSLCipher' => OpenSSL::CIPHER_AES_128_GCM,
'fileOpenSSLTag' => bin2hex($tag),
'fileOpenSSLIV' => bin2hex($iv),
'fileOpenSSLTag' => bin2hex($tag),
'fileOpenSSLIV' => bin2hex($iv),
]);
if(false === $file) {
if (false === $file) {
throw new Exception('Failed saving file to DB', 500);
}
$audit
->setParam('event', 'storage.upload')
->setParam('resource', 'storage/file/' . $file->getUid())
->setParam('resource', 'storage/file/'.$file->getUid())
;
$usage
@ -532,11 +527,10 @@ $utopia->put('/v1/storage/files/:fileId')
->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of write permissions. [Learn more about permissions and roles](/docs/permissions).', true)
->param('folderId', '', function () {return new UID();}, 'Folder to associate files with.', true)
->action(
function($fileId, $read, $write, $folderId) use ($response, $projectDB)
{
function ($fileId, $read, $write, $folderId) use ($response, $projectDB) {
$file = $projectDB->getDocument($fileId);
if(empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
@ -548,7 +542,7 @@ $utopia->put('/v1/storage/files/:fileId')
'folderId' => $folderId,
]));
if(false === $file) {
if (false === $file) {
throw new Exception('Failed saving file to DB', 500);
}
@ -564,24 +558,24 @@ $utopia->delete('/v1/storage/files/:fileId')
->label('sdk.description', 'Delete a file by its unique ID. Only users with write permissions have access to delete this resource.')
->param('fileId', '', function () {return new UID();}, 'File unique ID.')
->action(
function($fileId) use ($response, $projectDB, $audit, $usage) {
function ($fileId) use ($response, $projectDB, $audit, $usage) {
$file = $projectDB->getDocument($fileId);
if(empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
$device = Storage::getDevice('local');
if($device->delete($file->getAttribute('path', ''))) {
if(!$projectDB->deleteDocument($fileId)) {
if ($device->delete($file->getAttribute('path', ''))) {
if (!$projectDB->deleteDocument($fileId)) {
throw new Exception('Failed to remove file from DB', 500);
}
}
$audit
->setParam('event', 'storage.delete')
->setParam('resource', 'storage/file/' . $file->getUid())
->setParam('resource', 'storage/file/'.$file->getUid())
;
$usage
@ -601,30 +595,29 @@ $utopia->get('/v1/storage/files/:fileId/scan')
->param('fileId', '', function () {return new UID();}, 'File unique ID.')
->param('storage', 'local', function () {return new WhiteList(['local']);})
->action(
function($fileId, $storage) use ($response, $request, $projectDB)
{
function ($fileId, $storage) use ($response, $request, $projectDB) {
$file = $projectDB->getDocument($fileId);
if(empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
$path = $file->getAttribute('path', '');
if (!file_exists($path)) {
throw new Exception('File not found in ' . $path, 404);
throw new Exception('File not found in '.$path, 404);
}
$compressor = new GZIP();
$device = Storage::getDevice($storage);
$device = Storage::getDevice($storage);
$source = $device->read($path);
if(!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
$request->getServer('_APP_OPENSSL_KEY_V' . $file->getAttribute('fileOpenSSLVersion')),
$request->getServer('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
0,
hex2bin($file->getAttribute('fileOpenSSLIV')),
hex2bin($file->getAttribute('fileOpenSSLTag'))
@ -641,4 +634,4 @@ $utopia->get('/v1/storage/files/:fileId/scan')
//$response->json($antiVirus->continueScan($device->getRoot()));
}
);
);

View file

@ -26,11 +26,10 @@ $utopia->get('/v1/teams')
->label('sdk.description', 'Get a list of all the current user teams. You can use the query params to filter your results. On admin mode, this endpoint will return a list of all of the project teams. [Learn more about different API modes](/docs/modes).')
->param('search', '', function () {return new Text(256);}, 'Search term to filter your list results.', true)
->param('limit', 25, function () {return new Range(0, 100);}, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0 , function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('offset', 0, function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () {return new WhiteList(['ASC', 'DESC']);}, 'Order result by ASC or DESC order.', true)
->action(
function($search, $limit, $offset, $orderType) use ($response, $projectDB)
{
function ($search, $limit, $offset, $orderType) use ($response, $projectDB) {
$results = $projectDB->getCollection([
'limit' => $limit,
'offset' => $offset,
@ -39,7 +38,7 @@ $utopia->get('/v1/teams')
'orderCast' => 'int',
'search' => $search,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_TEAMS
'$collection='.Database::SYSTEM_COLLECTION_TEAMS,
],
]);
@ -55,11 +54,10 @@ $utopia->get('/v1/teams/:teamId')
->label('sdk.description', 'Get team by its unique ID. All team members have read access for this resource.')
->param('teamId', '', function () {return new UID();}, 'Team unique ID.')
->action(
function($teamId) use ($response, $projectDB)
{
function ($teamId) use ($response, $projectDB) {
$team = $projectDB->getDocument($teamId);
if(empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
if (empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
throw new Exception('Team not found', 404);
}
@ -75,11 +73,10 @@ $utopia->get('/v1/teams/:teamId/members')
->label('sdk.description', 'Get team members by the team unique ID. All team members have read access for this list of resources.')
->param('teamId', '', function () {return new UID();}, 'Team unique ID.')
->action(
function($teamId) use ($response, $projectDB)
{
function ($teamId) use ($response, $projectDB) {
$team = $projectDB->getDocument($teamId);
if(empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
if (empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
throw new Exception('Team not found', 404);
}
@ -87,15 +84,15 @@ $utopia->get('/v1/teams/:teamId/members')
'limit' => 50,
'offset' => 0,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'teamId=' . $teamId
]
'$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'teamId='.$teamId,
],
]);
$users = [];
foreach ($memberships as $member) {
if(empty($member->getAttribute('userId', null))) {
if (empty($member->getAttribute('userId', null))) {
continue;
}
@ -109,9 +106,10 @@ $utopia->get('/v1/teams/:teamId/members')
}
usort($users, function ($a, $b) {
if($a['joined'] === 0 || $b['joined'] === 0) {
if ($a['joined'] === 0 || $b['joined'] === 0) {
return $b['joined'] - $a['joined'];
}
return $a['joined'] - $b['joined'];
});
@ -128,15 +126,14 @@ $utopia->post('/v1/teams')
->param('name', null, function () {return new Text(100);}, 'Team name.')
->param('roles', ['owner'], function () {return new ArrayList(new Text(128));}, 'User roles array. Use this param to set the roles in the team for the user who created the team. The default role is **owner**, a role can be any string.', true)
->action(
function($name, $roles) use ($response, $projectDB, $user, $mode)
{
function ($name, $roles) use ($response, $projectDB, $user, $mode) {
Authorization::disable();
$team = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_TEAMS,
'$permissions' => [
'read' => ['team:{self}'],
'write' => ['team:{self}/owner'],
'$permissions' => [
'read' => ['team:{self}'],
'write' => ['team:{self}/owner'],
],
'name' => $name,
'sum' => ($mode !== APP_MODE_ADMIN) ? 1 : 0,
@ -145,16 +142,16 @@ $utopia->post('/v1/teams')
Authorization::enable();
if(false === $team) {
if (false === $team) {
throw new Exception('Failed saving team to DB', 500);
}
if($mode !== APP_MODE_ADMIN) { // Don't add user on admin mode
if ($mode !== APP_MODE_ADMIN) { // Don't add user on admin mode
$membership = new Document([
'$collection' => Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'$permissions' => [
'read' => ['user:' . $user->getUid(), 'team:' . $team->getUid()],
'write' => ['user:' . $user->getUid(), 'team:' . $team->getUid() . '/owner'],
'$permissions' => [
'read' => ['user:'.$user->getUid(), 'team:'.$team->getUid()],
'write' => ['user:'.$user->getUid(), 'team:'.$team->getUid().'/owner'],
],
'userId' => $user->getUid(),
'teamId' => $team->getUid(),
@ -170,7 +167,7 @@ $utopia->post('/v1/teams')
$user = $projectDB->updateDocument($user->getArrayCopy());
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
}
@ -191,11 +188,10 @@ $utopia->put('/v1/teams/:teamId')
->param('teamId', '', function () {return new UID();}, 'Team unique ID.')
->param('name', null, function () {return new Text(100);}, 'Team name.')
->action(
function($teamId, $name) use ($response, $projectDB)
{
function ($teamId, $name) use ($response, $projectDB) {
$team = $projectDB->getDocument($teamId);
if(empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
if (empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
throw new Exception('Team not found', 404);
}
@ -203,7 +199,7 @@ $utopia->put('/v1/teams/:teamId')
'name' => $name,
]));
if(false === $team) {
if (false === $team) {
throw new Exception('Failed saving team to DB', 500);
}
@ -219,11 +215,10 @@ $utopia->delete('/v1/teams/:teamId')
->label('sdk.description', 'Delete team by its unique ID. Only team owners have write access for this resource.')
->param('teamId', '', function () {return new UID();}, 'Team unique ID.')
->action(
function($teamId) use ($response, $projectDB)
{
function ($teamId) use ($response, $projectDB) {
$team = $projectDB->getDocument($teamId);
if(empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
if (empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
throw new Exception('Team not found', 404);
}
@ -231,18 +226,18 @@ $utopia->delete('/v1/teams/:teamId')
'limit' => 2000, // TODO add members limit
'offset' => 0,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'teamId=' . $teamId
]
'$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'teamId='.$teamId,
],
]);
foreach ($memberships as $member) {
if(!$projectDB->deleteDocument($member)) {
if (!$projectDB->deleteDocument($member)) {
throw new Exception('Failed to remove membership for team from DB', 500);
}
}
if(!$projectDB->deleteDocument($teamId)) {
if (!$projectDB->deleteDocument($teamId)) {
throw new Exception('Failed to remove team from DB', 500);
}
@ -264,12 +259,11 @@ $utopia->post('/v1/teams/:teamId/memberships')
->param('roles', [], function () {return new ArrayList(new Text(128));}, 'Invite roles array. Learn more about [roles and permissions](/docs/permissions).')
->param('redirect', '', function () use ($clients) {return new Host($clients);}, 'Reset page to redirect user back to your app from the invitation email.')
->action(
function($teamId, $email, $name, $roles, $redirect) use ($request, $response, $register, $project, $user, $audit, $projectDB)
{
function ($teamId, $email, $name, $roles, $redirect) use ($request, $response, $register, $project, $user, $audit, $projectDB) {
$name = (empty($name)) ? $email : $name;
$team = $projectDB->getDocument($teamId);
if(empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
if (empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
throw new Exception('Team not found', 404);
}
@ -277,21 +271,21 @@ $utopia->post('/v1/teams/:teamId/memberships')
'limit' => 50,
'offset' => 0,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'teamId=' . $team->getUid()
]
'$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'teamId='.$team->getUid(),
],
]);
$invitee = $projectDB->getCollection([ // Get user by email address
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'email=' . $email
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'email='.$email,
],
]);
if(empty($invitee)) { // Create new user if no user with same email found
if (empty($invitee)) { // Create new user if no user with same email found
Authorization::disable();
@ -309,12 +303,12 @@ $utopia->post('/v1/teams/:teamId/memberships')
'confirm' => false,
'reset' => false,
'name' => $name,
'tokens' => []
'tokens' => [],
]);
Authorization::enable();
if(false === $invitee) {
if (false === $invitee) {
throw new Exception('Failed saving user to DB', 500);
}
}
@ -322,16 +316,16 @@ $utopia->post('/v1/teams/:teamId/memberships')
$isOwner = false;
foreach ($memberships as $member) {
if($member->getAttribute('userId') == $invitee->getUid()) {
if ($member->getAttribute('userId') == $invitee->getUid()) {
throw new Exception('User has already been invited or is already a member of this team', 400);
}
if($member->getAttribute('userId') == $user->getUid() && in_array('owner', $member->getAttribute('roles', []))) {
if ($member->getAttribute('userId') == $user->getUid() && in_array('owner', $member->getAttribute('roles', []))) {
$isOwner = true;
}
}
if(!$isOwner) {
if (!$isOwner) {
throw new Exception('User is not allowed to send invitations for this team', 401);
}
@ -339,9 +333,9 @@ $utopia->post('/v1/teams/:teamId/memberships')
$membership = new Document([
'$collection' => Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'$permissions' => [
'read' => ['*'],
'write' => ['user:' . $invitee->getUid(), 'team:' . $team->getUid() . '/owner'],
'$permissions' => [
'read' => ['*'],
'write' => ['user:'.$invitee->getUid(), 'team:'.$team->getUid().'/owner'],
],
'userId' => $invitee->getUid(),
'teamId' => $team->getUid(),
@ -354,7 +348,7 @@ $utopia->post('/v1/teams/:teamId/memberships')
$membership = $projectDB->createDocument($membership->getArrayCopy());
if(false === $membership) {
if (false === $membership) {
throw new Exception('Failed saving membership to DB', 500);
}
@ -362,7 +356,7 @@ $utopia->post('/v1/teams/:teamId/memberships')
$redirect['query'] = Template::mergeQuery(((isset($redirect['query'])) ? $redirect['query'] : ''), ['inviteId' => $membership->getUid(), 'teamId' => $team->getUid(), 'userId' => $invitee->getUid(), 'secret' => $secret]);
$redirect = Template::unParseURL($redirect);
$body = new Template(__DIR__ . '/../config/locale/templates/' . Locale::getText('auth.emails.invitation.body'));
$body = new Template(__DIR__.'/../config/locale/templates/'.Locale::getText('auth.emails.invitation.body'));
$body
->setParam('{{direction}}', Locale::getText('settings.direction'))
->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]']))
@ -376,13 +370,12 @@ $utopia->post('/v1/teams/:teamId/memberships')
$mail->addAddress($email, $name);
$mail->Subject = sprintf(Locale::getText('auth.emails.invitation.title'), $team->getAttribute('name', '[TEAM-NAME]'), $project->getAttribute('name', ['[APP-NAME]']));
$mail->Body = $body->render();
$mail->Body = $body->render();
$mail->AltBody = strip_tags($body->render());
try {
$mail->send();
}
catch(\Exception $error) {
} catch (\Exception $error) {
//throw new Exception('Problem sending mail: ' . $error->getError(), 500);
}
@ -407,27 +400,26 @@ $utopia->post('/v1/teams/:teamId/memberships/:inviteId/resend')
->param('inviteId', '', function () {return new UID();}, 'Invite unique ID.')
->param('redirect', '', function () use ($clients) {return new Host($clients);}, 'Reset page to redirect user back to your app from the invitation email.')
->action(
function($teamId, $inviteId, $redirect) use ($response, $register, $project, $user, $audit, $projectDB)
{
function ($teamId, $inviteId, $redirect) use ($response, $register, $project, $user, $audit, $projectDB) {
$membership = $projectDB->getDocument($inviteId);
if(empty($membership->getUid()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $membership->getCollection()) {
if (empty($membership->getUid()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $membership->getCollection()) {
throw new Exception('Membership not found', 404);
}
$team = $projectDB->getDocument($membership->getAttribute('teamId'));
if(empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
if (empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
throw new Exception('Team not found', 404);
}
if($team->getUid() !== $teamId) {
if ($team->getUid() !== $teamId) {
throw new Exception('Team IDs don\'t match', 404);
}
$invitee = $projectDB->getDocument($membership->getAttribute('userId'));
if(empty($invitee->getUid()) || Database::SYSTEM_COLLECTION_USERS != $invitee->getCollection()) {
if (empty($invitee->getUid()) || Database::SYSTEM_COLLECTION_USERS != $invitee->getCollection()) {
throw new Exception('User not found', 404);
}
@ -435,7 +427,7 @@ $utopia->post('/v1/teams/:teamId/memberships/:inviteId/resend')
$membership = $projectDB->updateDocument(array_merge($membership->getArrayCopy(), ['secret' => Auth::hash($secret)]));
if(false === $membership) {
if (false === $membership) {
throw new Exception('Failed updating membership to DB', 500);
}
@ -443,7 +435,7 @@ $utopia->post('/v1/teams/:teamId/memberships/:inviteId/resend')
$redirect['query'] = Template::mergeQuery(((isset($redirect['query'])) ? $redirect['query'] : ''), ['inviteId' => $membership->getUid(), 'userId' => $membership->getAttribute('userId'), 'secret' => $secret]);
$redirect = Template::unParseURL($redirect);
$body = new Template(__DIR__ . '/../config/locale/templates/' . Locale::getText('auth.emails.invitation.body'));
$body = new Template(__DIR__.'/../config/locale/templates/'.Locale::getText('auth.emails.invitation.body'));
$body
->setParam('{{direction}}', Locale::getText('settings.direction'))
->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]']))
@ -457,16 +449,15 @@ $utopia->post('/v1/teams/:teamId/memberships/:inviteId/resend')
$mail->addAddress($invitee->getAttribute('email'), $invitee->getAttribute('name'));
$mail->Subject = sprintf(Locale::getText('auth.emails.invitation.title'), $team->getAttribute('name', '[TEAM-NAME]'), $project->getAttribute('name', ['[APP-NAME]']));
$mail->Body = $body->render();
$mail->Body = $body->render();
$mail->AltBody = strip_tags($body->render());
try {
$mail->send();
}
catch(\Exception $error) {
} catch (\Exception $error) {
//throw new Exception('Problem sending mail: ' . $error->getError(), 500);
}
$audit
->setParam('userId', $user->getUid())
->setParam('event', 'auth.invite.resend')
@ -493,65 +484,68 @@ $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status')
->param('success', null, function () use ($clients) {return new Host($clients);}, 'Redirect when registration succeed', true)
->param('failure', null, function () use ($clients) {return new Host($clients);}, 'Redirect when registration failed', true)
->action(
function($teamId, $inviteId, $userId, $secret, $success, $failure) use ($response, $request, $user, $audit, $projectDB)
{
function ($teamId, $inviteId, $userId, $secret, $success, $failure) use ($response, $request, $user, $audit, $projectDB) {
$invite = $projectDB->getDocument($inviteId);
if(empty($invite->getUid()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $invite->getCollection()) {
if($failure) {
if (empty($invite->getUid()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $invite->getCollection()) {
if ($failure) {
$response->redirect($failure);
return;
}
throw new Exception('Invite not found', 404);
}
if($invite->getAttribute('teamId')->getUid() !== $teamId) {
if ($invite->getAttribute('teamId')->getUid() !== $teamId) {
throw new Exception('Team IDs don\'t match', 404);
}
$team = $projectDB->getDocument($teamId);
if(empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
if (empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
throw new Exception('Team not found', 404);
}
if(Auth::hash($secret) !== $invite->getAttribute('secret')) {
if($failure) {
if (Auth::hash($secret) !== $invite->getAttribute('secret')) {
if ($failure) {
$response->redirect($failure);
return;
}
throw new Exception('Secret key not valid', 401);
}
if($userId != $invite->getAttribute('userId')) {
if($failure) {
if ($userId != $invite->getAttribute('userId')) {
if ($failure) {
$response->redirect($failure);
return;
}
throw new Exception('Invite not belong to current user (' . $user->getAttribute('email') . ')', 401);
throw new Exception('Invite not belong to current user ('.$user->getAttribute('email').')', 401);
}
if(empty($user->getUid())) {
if (empty($user->getUid())) {
$user = $projectDB->getCollection([ // Get user
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'$uid=' . $userId
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'$uid='.$userId,
],
]);
}
if($invite->getAttribute('userId') !== $user->getUid()) {
if($failure) {
if ($invite->getAttribute('userId') !== $user->getUid()) {
if ($failure) {
$response->redirect($failure);
return;
}
throw new Exception('Invite not belong to current user (' . $user->getAttribute('email') . ')', 401);
throw new Exception('Invite not belong to current user ('.$user->getAttribute('email').')', 401);
}
$invite // Attach user to team
@ -569,19 +563,19 @@ $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status')
$user->setAttribute('tokens', new Document([
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:' . $user->getUid()], 'write' => ['user:' . $user->getUid()]],
'$permissions' => ['read' => ['user:'.$user->getUid()], 'write' => ['user:'.$user->getUid()]],
'type' => Auth::TOKEN_TYPE_LOGIN,
'secret' => Auth::hash($secret), // On way hash encryption to protect DB leak
'expire' => $expiry,
'userAgent' => $request->getServer('HTTP_USER_AGENT', 'UNKNOWN'),
'ip' => $request->getIP(),
]),Document::SET_TYPE_APPEND);
]), Document::SET_TYPE_APPEND);
Authorization::setRole('user:' . $userId);
Authorization::setRole('user:'.$userId);
$user = $projectDB->updateDocument($user->getArrayCopy());
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
@ -589,7 +583,7 @@ $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status')
'sum' => $team->getAttribute('sum', 0) + 1,
]));
if(false === $team) {
if (false === $team) {
throw new Exception('Failed saving team to DB', 500);
}
@ -600,7 +594,7 @@ $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status')
$response->addCookie(Auth::$cookieName, Auth::encodeSession($user->getUid(), $secret), $expiry, '/', COOKIE_DOMAIN, ('https' == $request->getServer('REQUEST_SCHEME', 'https')), true);
if($success) {
if ($success) {
$response->redirect($success);
}
@ -613,29 +607,28 @@ $utopia->delete('/v1/teams/:teamId/memberships/:inviteId')
->label('scope', 'account')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'deleteTeamMembership')
->label('sdk.description', "This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member.")
->label('sdk.description', 'This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member.')
->param('teamId', '', function () {return new UID();}, 'Team unique ID.')
->param('inviteId', '', function () {return new UID();}, 'Invite unique ID')
->action(
function($teamId, $inviteId) use ($response, $projectDB, $audit)
{
function ($teamId, $inviteId) use ($response, $projectDB, $audit) {
$invite = $projectDB->getDocument($inviteId);
if(empty($invite->getUid()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $invite->getCollection()) {
if (empty($invite->getUid()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $invite->getCollection()) {
throw new Exception('Invite not found', 404);
}
if($invite->getAttribute('teamId') !== $teamId) {
if ($invite->getAttribute('teamId') !== $teamId) {
throw new Exception('Team IDs don\'t match', 404);
}
$team = $projectDB->getDocument($teamId);
if(empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
if (empty($team->getUid()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
throw new Exception('Team not found', 404);
}
if(!$projectDB->deleteDocument($invite->getUid())) {
if (!$projectDB->deleteDocument($invite->getUid())) {
throw new Exception('Failed to remove membership from DB', 500);
}
@ -643,7 +636,7 @@ $utopia->delete('/v1/teams/:teamId/memberships/:inviteId')
'sum' => $team->getAttribute('sum', 0) - 1,
]));
if(false === $team) {
if (false === $team) {
throw new Exception('Failed saving team to DB', 500);
}
@ -654,4 +647,4 @@ $utopia->delete('/v1/teams/:teamId/memberships/:inviteId')
$response->noContent();
}
);
);

View file

@ -25,11 +25,10 @@ $utopia->get('/v1/users')
->label('sdk.description', 'Get a list of all the project users. You can use the query params to filter your results.')
->param('search', '', function () {return new Text(256);}, 'Search term to filter your list results.', true)
->param('limit', 25, function () {return new Range(0, 100);}, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0 , function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('offset', 0, function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () {return new WhiteList(['ASC', 'DESC']);}, 'Order result by ASC or DESC order.', true)
->action(
function($search, $limit, $offset, $orderType) use ($response, $projectDB, $providers)
{
function ($search, $limit, $offset, $orderType) use ($response, $projectDB, $providers) {
$results = $projectDB->getCollection([
'limit' => $limit,
'offset' => $offset,
@ -38,19 +37,19 @@ $utopia->get('/v1/users')
'orderCast' => 'int',
'search' => $search,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS
'$collection='.Database::SYSTEM_COLLECTION_USERS,
],
]);
$oauthKeys = [];
foreach($providers as $key => $provider) {
if(!$provider['enabled']) {
foreach ($providers as $key => $provider) {
if (!$provider['enabled']) {
continue;
}
$oauthKeys[] = 'oauth' . ucfirst($key);
$oauthKeys[] = 'oauth' . ucfirst($key) . 'AccessToken';
$oauthKeys[] = 'oauth'.ucfirst($key);
$oauthKeys[] = 'oauth'.ucfirst($key).'AccessToken';
}
$results = array_map(function ($value) use ($oauthKeys) { /* @var $value \Database\Document */
@ -77,23 +76,22 @@ $utopia->get('/v1/users/:userId')
->label('sdk.description', 'Get user by its unique ID.')
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->action(
function($userId) use ($response, $projectDB, $providers)
{
function ($userId) use ($response, $projectDB, $providers) {
$user = $projectDB->getDocument($userId);
if(empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
if (empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
throw new Exception('User not found', 404);
}
$oauthKeys = [];
foreach($providers as $key => $provider) {
if(!$provider['enabled']) {
foreach ($providers as $key => $provider) {
if (!$provider['enabled']) {
continue;
}
$oauthKeys[] = 'oauth' . ucfirst($key);
$oauthKeys[] = 'oauth' . ucfirst($key) . 'AccessToken';
$oauthKeys[] = 'oauth'.ucfirst($key);
$oauthKeys[] = 'oauth'.ucfirst($key).'AccessToken';
}
$response->json(array_merge($user->getArrayCopy(array_merge(
@ -116,23 +114,22 @@ $utopia->get('/v1/users/:userId/prefs')
->label('sdk.description', 'Get user preferences by its unique ID.')
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->action(
function($userId) use ($response, $projectDB) {
function ($userId) use ($response, $projectDB) {
$user = $projectDB->getDocument($userId);
if(empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
if (empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
throw new Exception('User not found', 404);
}
$prefs = $user->getAttribute('prefs', '');
$prefs = $user->getAttribute('prefs', '');
if(empty($prefs)) {
if (empty($prefs)) {
$prefs = '[]';
}
try {
$prefs = json_decode($prefs, true);
}
catch (\Exception $error) {
} catch (\Exception $error) {
throw new Exception('Failed to parse prefs', 500);
}
@ -148,25 +145,25 @@ $utopia->get('/v1/users/:userId/sessions')
->label('sdk.description', 'Get user sessions list by its unique ID.')
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->action(
function($userId) use ($response, $projectDB) {
function ($userId) use ($response, $projectDB) {
$user = $projectDB->getDocument($userId);
if(empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
if (empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
throw new Exception('User not found', 404);
}
$tokens = $user->getAttribute('tokens', []);
$reader = new Reader(__DIR__ . '/../db/GeoLite2/GeoLite2-Country.mmdb');
$sessions = [];
$index = 0;
$countries = Locale::getText('countries');
$tokens = $user->getAttribute('tokens', []);
$reader = new Reader(__DIR__.'/../db/GeoLite2/GeoLite2-Country.mmdb');
$sessions = [];
$index = 0;
$countries = Locale::getText('countries');
foreach($tokens as $token) { /* @var $token Document */
if(Auth::TOKEN_TYPE_LOGIN != $token->getAttribute('type')) {
foreach ($tokens as $token) { /* @var $token Document */
if (Auth::TOKEN_TYPE_LOGIN != $token->getAttribute('type')) {
continue;
}
$userAgent = (!empty($token->getAttribute('userAgent'))) ? $token->getAttribute('userAgent') : 'UNKNOWN';
$userAgent = (!empty($token->getAttribute('userAgent'))) ? $token->getAttribute('userAgent') : 'UNKNOWN';
$dd = new DeviceDetector($userAgent);
@ -176,27 +173,26 @@ $utopia->get('/v1/users/:userId/sessions')
$dd->parse();
$sessions[$index] = [
'$uid' => $token->getUid(),
'OS' => $dd->getOs(),
'client' => $dd->getClient(),
'device' => $dd->getDevice(),
'brand' => $dd->getBrand(),
'model' => $dd->getModel(),
'ip' => $token->getAttribute('ip', ''),
'geo' => [],
'$uid' => $token->getUid(),
'OS' => $dd->getOs(),
'client' => $dd->getClient(),
'device' => $dd->getDevice(),
'brand' => $dd->getBrand(),
'model' => $dd->getModel(),
'ip' => $token->getAttribute('ip', ''),
'geo' => [],
];
try {
$record = $reader->country($token->getAttribute('ip', ''));
$sessions[$index]['geo']['isoCode'] = strtolower($record->country->isoCode);
$sessions[$index]['geo']['country'] = (isset($countries[$record->country->isoCode])) ? $countries[$record->country->isoCode] : Locale::getText('locale.country.unknown');
}
catch(\Exception $e) {
} catch (\Exception $e) {
$sessions[$index]['geo']['isoCode'] = '--';
$sessions[$index]['geo']['country'] = Locale::getText('locale.country.unknown');
}
$index++;
++$index;
}
$response->json($sessions);
@ -211,25 +207,25 @@ $utopia->get('/v1/users/:userId/logs')
->label('sdk.description', 'Get user activity logs list by its unique ID.')
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->action(
function($userId) use ($response, $register, $projectDB, $project) {
function ($userId) use ($response, $register, $projectDB, $project) {
$user = $projectDB->getDocument($userId);
if(empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
if (empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
throw new Exception('User not found', 404);
}
$ad = new \Audit\Adapter\MySQL($register->get('db'));
$ad->setNamespace('app_' . $project->getUid());
$ad->setNamespace('app_'.$project->getUid());
$au = new \Audit\Audit($ad, $user->getUid(), $user->getAttribute('type'), '', '', '');
$countries = Locale::getText('countries');
$countries = Locale::getText('countries');
$logs = $au->getLogsByUser($user->getUid(), $user->getAttribute('type', 0));
$reader = new Reader(__DIR__ . '/../db/GeoLite2/GeoLite2-Country.mmdb');
$output = [];
$reader = new Reader(__DIR__.'/../db/GeoLite2/GeoLite2-Country.mmdb');
$output = [];
foreach($logs as $i => &$log) {
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
foreach ($logs as $i => &$log) {
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
$dd = new DeviceDetector($log['userAgent']);
@ -238,15 +234,15 @@ $utopia->get('/v1/users/:userId/logs')
$dd->parse();
$output[$i] = [
'event' => $log['event'],
'ip' => $log['ip'],
'time' => strtotime($log['time']),
'OS' => $dd->getOs(),
'client' => $dd->getClient(),
'device' => $dd->getDevice(),
'brand' => $dd->getBrand(),
'model' => $dd->getModel(),
'geo' => [],
'event' => $log['event'],
'ip' => $log['ip'],
'time' => strtotime($log['time']),
'OS' => $dd->getOs(),
'client' => $dd->getClient(),
'device' => $dd->getDevice(),
'brand' => $dd->getBrand(),
'model' => $dd->getModel(),
'geo' => [],
];
try {
@ -254,10 +250,9 @@ $utopia->get('/v1/users/:userId/logs')
$output[$i]['geo']['isoCode'] = strtolower($record->country->isoCode);
$output[$i]['geo']['country'] = $record->country->name;
$output[$i]['geo']['country'] = (isset($countries[$record->country->isoCode])) ? $countries[$record->country->isoCode] : Locale::getText('locale.country.unknown');
}
catch(\Exception $e) {
} catch (\Exception $e) {
$output[$i]['geo']['isoCode'] = '--';
$output[$i]['geo']['country'] = Locale::getText('locale.country.unknown');;
$output[$i]['geo']['country'] = Locale::getText('locale.country.unknown');
}
}
@ -275,17 +270,17 @@ $utopia->post('/v1/users')
->param('password', '', function () {return new Password();}, 'User account password.')
->param('name', '', function () {return new Text(100);}, 'User account name.', true)
->action(
function($email, $password, $name) use ($response, $register, $projectDB, $providers) {
function ($email, $password, $name) use ($response, $register, $projectDB, $providers) {
$profile = $projectDB->getCollection([ // Get user by email address
'limit' => 1,
'first' => true,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_USERS,
'email=' . $email
]
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'email='.$email,
],
]);
if(!empty($profile)) {
if (!empty($profile)) {
throw new Exception('User already registered', 400);
}
@ -304,16 +299,16 @@ $utopia->post('/v1/users')
'reset' => false,
'name' => $name,
]);
$oauthKeys = [];
foreach($providers as $key => $provider) {
if(!$provider['enabled']) {
foreach ($providers as $key => $provider) {
if (!$provider['enabled']) {
continue;
}
$oauthKeys[] = 'oauth' . ucfirst($key);
$oauthKeys[] = 'oauth' . ucfirst($key) . 'AccessToken';
$oauthKeys[] = 'oauth'.ucfirst($key);
$oauthKeys[] = 'oauth'.ucfirst($key).'AccessToken';
}
$response
@ -336,13 +331,12 @@ $utopia->patch('/v1/users/:userId/status')
->label('sdk.method', 'updateUserStatus')
->label('sdk.description', 'Update user status by its unique ID.')
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->param('status', '', function () {return new WhiteList([Auth::USER_STATUS_ACTIVATED, Auth::USER_STATUS_BLOCKED, Auth::USER_STATUS_UNACTIVATED]);}, 'User Status code. To activate the user pass ' . Auth::USER_STATUS_ACTIVATED . ', to blocking the user pass ' . Auth::USER_STATUS_BLOCKED . ' and for disabling the user pass ' . Auth::USER_STATUS_UNACTIVATED)
->param('status', '', function () {return new WhiteList([Auth::USER_STATUS_ACTIVATED, Auth::USER_STATUS_BLOCKED, Auth::USER_STATUS_UNACTIVATED]);}, 'User Status code. To activate the user pass '.Auth::USER_STATUS_ACTIVATED.', to blocking the user pass '.Auth::USER_STATUS_BLOCKED.' and for disabling the user pass '.Auth::USER_STATUS_UNACTIVATED)
->action(
function($userId, $status) use ($response, $projectDB)
{
function ($userId, $status) use ($response, $projectDB) {
$user = $projectDB->getDocument($userId);
if(empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
if (empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
throw new Exception('User not found', 404);
}
@ -350,7 +344,7 @@ $utopia->patch('/v1/users/:userId/status')
'status' => $status,
]));
if(false === $user) {
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
@ -369,20 +363,18 @@ $utopia->delete('/v1/users/:userId/sessions/:session')
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->param('sessionId', null, function () {return new UID();}, 'User unique session ID.')
->action(
function($userId, $sessionId) use ($response, $request, $projectDB)
{
function ($userId, $sessionId) use ($response, $request, $projectDB) {
$user = $projectDB->getDocument($userId);
if(empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
if (empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
throw new Exception('User not found', 404);
}
$tokens = $user->getAttribute('tokens', []);
foreach($tokens as $token) { /* @var $token Document */
if($sessionId == $token->getUid()) {
if(!$projectDB->deleteDocument($token->getUid())) {
foreach ($tokens as $token) { /* @var $token Document */
if ($sessionId == $token->getUid()) {
if (!$projectDB->deleteDocument($token->getUid())) {
throw new Exception('Failed to remove token from DB', 500);
}
}
@ -401,22 +393,21 @@ $utopia->delete('/v1/users/:userId/sessions')
->label('abuse-limit', 100)
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->action(
function($userId) use ($response, $request, $projectDB)
{
function ($userId) use ($response, $request, $projectDB) {
$user = $projectDB->getDocument($userId);
if(empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
if (empty($user->getUid()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
throw new Exception('User not found', 404);
}
$tokens = $user->getAttribute('tokens', []);
foreach($tokens as $token) { /* @var $token Document */
if(!$projectDB->deleteDocument($token->getUid())) {
foreach ($tokens as $token) { /* @var $token Document */
if (!$projectDB->deleteDocument($token->getUid())) {
throw new Exception('Failed to remove token from DB', 500);
}
}
$response->json(array('result' => 'success'));
}
);
);