Added webhooks event and audit logs for resources
This commit is contained in:
parent
128ae4239c
commit
a9abf52da9
|
@ -48,7 +48,6 @@ $utopia->get('/v1/account')
|
|||
'$uid',
|
||||
'email',
|
||||
'registration',
|
||||
'confirm',
|
||||
'name',
|
||||
],
|
||||
$oauthKeys
|
||||
|
@ -216,10 +215,9 @@ $utopia->post('/v1/account')
|
|||
->label('abuse-limit', 10)
|
||||
->param('email', '', function () { return new Email(); }, 'Account email')
|
||||
->param('password', '', function () { return new Password(); }, 'User password')
|
||||
->param('confirm', '', function () use ($clients) { return new Host($clients); }, 'Confirmation URL to redirect user after confirm token has been sent to user email') // TODO add our own built-in confirm page
|
||||
->param('name', '', function () { return new Text(100); }, 'User name', true)
|
||||
->action(
|
||||
function ($email, $password, $confirm, $name) use ($request, $response, $register, $audit, $projectDB, $project, $webhook) {
|
||||
function ($email, $password, $name) use ($request, $response, $audit, $projectDB, $project, $webhook) {
|
||||
if ('console' === $project->getUid()) {
|
||||
$whitlistEmails = $project->getAttribute('authWhitelistEmails');
|
||||
$whitlistIPs = $project->getAttribute('authWhitelistIPs');
|
||||
|
@ -252,7 +250,6 @@ $utopia->post('/v1/account')
|
|||
}
|
||||
|
||||
$expiry = time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
$confirmSecret = Auth::tokenGenerator();
|
||||
$loginSecret = Auth::tokenGenerator();
|
||||
|
||||
Authorization::disable();
|
||||
|
@ -282,15 +279,6 @@ $utopia->post('/v1/account')
|
|||
Authorization::setRole('user:'.$user->getUid());
|
||||
|
||||
$user
|
||||
->setAttribute('tokens', new Document([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
|
||||
'$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)
|
||||
->setAttribute('tokens', new Document([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
|
||||
'$permissions' => ['read' => ['user:'.$user->getUid()], 'write' => ['user:'.$user->getUid()]],
|
||||
|
@ -308,39 +296,6 @@ $utopia->post('/v1/account')
|
|||
throw new Exception('Failed saving tokens to DB', 500);
|
||||
}
|
||||
|
||||
// Send email address confirmation email
|
||||
|
||||
$confirm = Template::parseURL($confirm);
|
||||
$confirm['query'] = Template::mergeQuery(((isset($confirm['query'])) ? $confirm['query'] : ''), ['userId' => $user->getUid(), 'token' => $confirmSecret]);
|
||||
$confirm = Template::unParseURL($confirm);
|
||||
|
||||
$body = new Template(__DIR__.'/../../config/locales/templates/'.Locale::getText('auth.emails.confirm.body'));
|
||||
$body
|
||||
->setParam('{{direction}}', Locale::getText('settings.direction'))
|
||||
->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]']))
|
||||
->setParam('{{name}}', $name)
|
||||
->setParam('{{redirect}}', $confirm)
|
||||
;
|
||||
|
||||
$mail = $register->get('smtp'); /* @var $mail \PHPMailer\PHPMailer\PHPMailer */
|
||||
|
||||
$mail->addAddress($email, $name);
|
||||
|
||||
$mail->Subject = Locale::getText('auth.emails.confirm.title');
|
||||
$mail->Body = $body->render();
|
||||
$mail->AltBody = strip_tags($body->render());
|
||||
|
||||
try {
|
||||
$mail->send();
|
||||
} catch (\Exception $error) {
|
||||
// if($failure) {
|
||||
// $response->redirect($failure);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// throw new Exception('Problem sending mail: ' . $error->getMessage(), 500);
|
||||
}
|
||||
|
||||
$webhook
|
||||
->setParam('payload', [
|
||||
'name' => $name,
|
||||
|
@ -360,9 +315,81 @@ $utopia->post('/v1/account')
|
|||
}
|
||||
);
|
||||
|
||||
$utopia->post('/v1/account/sessions')
|
||||
->desc('Login')
|
||||
->label('webhook', 'account.sessions.create')
|
||||
->label('scope', 'account')
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'createAccountSession')
|
||||
->label('sdk.description', '/docs/references/account/create-account-session.md')
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},email:{param-email}')
|
||||
->param('email', '', function () { return new Email(); }, 'User account email address')
|
||||
->param('password', '', function () { return new Password(); }, 'User account password')
|
||||
->action(
|
||||
function ($email, $password) 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,
|
||||
],
|
||||
]);
|
||||
|
||||
if (!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) {
|
||||
$audit
|
||||
//->setParam('userId', $profile->getUid())
|
||||
->setParam('event', 'auth.failure')
|
||||
;
|
||||
|
||||
throw new Exception('Invalid credentials', 401); // Wrong password or username
|
||||
}
|
||||
|
||||
$expiry = time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
$secret = Auth::tokenGenerator();
|
||||
|
||||
$profile->setAttribute('tokens', new Document([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
|
||||
'$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);
|
||||
|
||||
Authorization::setRole('user:'.$profile->getUid());
|
||||
|
||||
$profile = $projectDB->updateDocument($profile->getArrayCopy());
|
||||
|
||||
if (false === $profile) {
|
||||
throw new Exception('Failed saving user to DB', 500);
|
||||
}
|
||||
|
||||
$webhook
|
||||
->setParam('payload', [
|
||||
'name' => $profile->getAttribute('name', ''),
|
||||
'email' => $profile->getAttribute('email', ''),
|
||||
])
|
||||
;
|
||||
|
||||
$audit
|
||||
->setParam('userId', $profile->getUid())
|
||||
->setParam('event', 'auth.login')
|
||||
;
|
||||
|
||||
$response
|
||||
->addCookie(Auth::$cookieName, Auth::encodeSession($profile->getUid(), $secret), $expiry, '/', COOKIE_DOMAIN, ('https' == $request->getServer('REQUEST_SCHEME', 'https')), true, COOKIE_SAMESITE);
|
||||
|
||||
$response
|
||||
->json(array('result' => 'success'));
|
||||
}
|
||||
);
|
||||
|
||||
$utopia->patch('/v1/account/name')
|
||||
->desc('Update Account Name')
|
||||
->label('webhook', 'account.update-account-name')
|
||||
->label('webhook', 'account.update.name')
|
||||
->label('scope', 'account')
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'updateAccountName')
|
||||
|
@ -386,7 +413,7 @@ $utopia->patch('/v1/account/name')
|
|||
|
||||
$utopia->patch('/v1/account/password')
|
||||
->desc('Update Account Password')
|
||||
->label('webhook', 'account.update-account-password')
|
||||
->label('webhook', 'account.update.password')
|
||||
->label('scope', 'account')
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'updateAccountPassword')
|
||||
|
@ -415,7 +442,7 @@ $utopia->patch('/v1/account/password')
|
|||
|
||||
$utopia->patch('/v1/account/email')
|
||||
->desc('Update Account Email')
|
||||
->label('webhook', 'account.update-email')
|
||||
->label('webhook', 'account.update.email')
|
||||
->label('scope', 'account')
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'updateEmail')
|
||||
|
@ -459,7 +486,7 @@ $utopia->patch('/v1/account/email')
|
|||
|
||||
$utopia->patch('/v1/account/prefs')
|
||||
->desc('Update Account Prefs')
|
||||
->label('webhook', 'account')
|
||||
->label('webhook', 'account.update.prefs')
|
||||
->label('scope', 'account')
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'updatePrefs')
|
||||
|
|
|
@ -160,6 +160,7 @@ $utopia->post('/v1/database')
|
|||
$utopia->put('/v1/database/:collectionId')
|
||||
->desc('Update Collection')
|
||||
->label('scope', 'collections.write')
|
||||
->label('webhook', 'database.collections.update')
|
||||
->label('sdk.namespace', 'database')
|
||||
->label('sdk.method', 'updateCollection')
|
||||
->label('sdk.description', '/docs/references/database/update-collection.md')
|
||||
|
@ -169,7 +170,7 @@ $utopia->put('/v1/database/:collectionId')
|
|||
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
|
||||
->param('rules', [], function () use ($projectDB) { return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES], ['$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => ['read' => [], 'write' => []]])); }, 'Array of [rule objects](/docs/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, $webhook, $audit) {
|
||||
$collection = $projectDB->getDocument($collectionId, false);
|
||||
|
||||
if (empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
|
||||
|
@ -203,6 +204,18 @@ $utopia->put('/v1/database/:collectionId')
|
|||
throw new Exception('Failed saving collection to DB', 500);
|
||||
}
|
||||
|
||||
$data = $collection->getArrayCopy();
|
||||
|
||||
$webhook
|
||||
->setParam('payload', $data)
|
||||
;
|
||||
|
||||
$audit
|
||||
->setParam('event', 'database.collections.update')
|
||||
->setParam('resource', 'database/collections/'.$data['$uid'])
|
||||
->setParam('data', $data)
|
||||
;
|
||||
|
||||
$response->json($collection->getArrayCopy());
|
||||
}
|
||||
);
|
||||
|
@ -210,12 +223,13 @@ $utopia->put('/v1/database/:collectionId')
|
|||
$utopia->delete('/v1/database/:collectionId')
|
||||
->desc('Delete Collection')
|
||||
->label('scope', 'collections.write')
|
||||
->label('webhook', 'database.collections.delete')
|
||||
->label('sdk.namespace', 'database')
|
||||
->label('sdk.method', 'deleteCollection')
|
||||
->label('sdk.description', '/docs/references/database/delete-collection.md')
|
||||
->param('collectionId', '', function () { return new UID(); }, 'Collection unique ID.')
|
||||
->action(
|
||||
function ($collectionId) use ($response, $projectDB, $audit) {
|
||||
function ($collectionId) use ($response, $projectDB, $webhook, $audit) {
|
||||
$collection = $projectDB->getDocument($collectionId, false);
|
||||
|
||||
if (empty($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
|
||||
|
@ -225,11 +239,17 @@ $utopia->delete('/v1/database/:collectionId')
|
|||
if (!$projectDB->deleteDocument($collectionId)) {
|
||||
throw new Exception('Failed to remove collection from DB', 500);
|
||||
}
|
||||
|
||||
$data = $collection->getArrayCopy();
|
||||
|
||||
$webhook
|
||||
->setParam('payload', $data)
|
||||
;
|
||||
|
||||
$audit
|
||||
->setParam('event', 'database.collections.create')
|
||||
->setParam('resource', 'database/collection/'.$collection->getUid())
|
||||
->setParam('data', $collection->getArrayCopy()) // Audit document in case of malicious or disastrous action
|
||||
->setParam('event', 'database.collections.delete')
|
||||
->setParam('resource', 'database/collections/'.$data['$uid'])
|
||||
->setParam('data', $data)
|
||||
;
|
||||
|
||||
$response->noContent();
|
||||
|
@ -454,7 +474,7 @@ $utopia->post('/v1/database/:collectionId/documents')
|
|||
|
||||
$utopia->patch('/v1/database/:collectionId/documents/:documentId')
|
||||
->desc('Update Document')
|
||||
->label('webhook', 'database.documents.patch')
|
||||
->label('webhook', 'database.documents.update')
|
||||
->label('scope', 'documents.write')
|
||||
->label('sdk.namespace', 'database')
|
||||
->label('sdk.method', 'updateDocument')
|
||||
|
@ -518,7 +538,7 @@ $utopia->patch('/v1/database/:collectionId/documents/:documentId')
|
|||
;
|
||||
|
||||
$audit
|
||||
->setParam('event', 'database.documents.patch')
|
||||
->setParam('event', 'database.documents.update')
|
||||
->setParam('resource', 'database/document/'.$data['$uid'])
|
||||
->setParam('data', $data)
|
||||
;
|
||||
|
@ -533,13 +553,14 @@ $utopia->patch('/v1/database/:collectionId/documents/:documentId')
|
|||
$utopia->delete('/v1/database/:collectionId/documents/:documentId')
|
||||
->desc('Delete Document')
|
||||
->label('scope', 'documents.write')
|
||||
->label('webhook', 'database.documents.delete')
|
||||
->label('sdk.namespace', 'database')
|
||||
->label('sdk.method', 'deleteDocument')
|
||||
->label('sdk.description', '/docs/references/database/delete-document.md')
|
||||
->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, $webhook, $isDev) {
|
||||
$collection = $projectDB->getDocument($collectionId, $isDev);
|
||||
$document = $projectDB->getDocument($documentId, $isDev);
|
||||
|
||||
|
@ -561,10 +582,16 @@ $utopia->delete('/v1/database/:collectionId/documents/:documentId')
|
|||
throw new Exception('Failed to remove document from DB', 500);
|
||||
}
|
||||
|
||||
$data = $document->getArrayCopy();
|
||||
|
||||
$webhook
|
||||
->setParam('payload', $data)
|
||||
;
|
||||
|
||||
$audit
|
||||
->setParam('event', 'database.documents.delete')
|
||||
->setParam('resource', 'database/document/'.$documentId)
|
||||
->setParam('data', $document->getArrayCopy()) // Audit document in case of malicious or disastrous action
|
||||
->setParam('resource', 'database/document/'.$data['$uid'])
|
||||
->setParam('data', $data) // Audit document in case of malicious or disastrous action
|
||||
;
|
||||
|
||||
$response->noContent();
|
||||
|
|
|
@ -398,6 +398,7 @@ $utopia->get('/v1/storage/files/:fileId/view')
|
|||
$utopia->post('/v1/storage/files')
|
||||
->desc('Create File')
|
||||
->label('scope', 'files.write')
|
||||
->label('webhook', 'storage.files.create')
|
||||
->label('sdk.namespace', 'storage')
|
||||
->label('sdk.method', 'createFile')
|
||||
->label('sdk.description', '/docs/references/storage/create-file.md')
|
||||
|
@ -407,7 +408,7 @@ $utopia->post('/v1/storage/files')
|
|||
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
|
||||
// ->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) {
|
||||
function ($files, $read, $write, $folderId = '') use ($request, $response, $user, $projectDB, $webhook, $audit, $usage) {
|
||||
$files = $request->getFiles('files');
|
||||
$read = (empty($read)) ? ['user:'.$user->getUid()] : $read;
|
||||
$write = (empty($write)) ? ['user:'.$user->getUid()] : $write;
|
||||
|
@ -513,9 +514,13 @@ $utopia->post('/v1/storage/files')
|
|||
throw new Exception('Failed saving file to DB', 500);
|
||||
}
|
||||
|
||||
$webhook
|
||||
->setParam('payload', $file->getArrayCopy())
|
||||
;
|
||||
|
||||
$audit
|
||||
->setParam('event', 'storage.upload')
|
||||
->setParam('resource', 'storage/file/'.$file->getUid())
|
||||
->setParam('event', 'storage.files.create')
|
||||
->setParam('resource', 'storage/files/'.$file->getUid())
|
||||
;
|
||||
|
||||
$usage
|
||||
|
@ -535,6 +540,7 @@ $utopia->post('/v1/storage/files')
|
|||
$utopia->put('/v1/storage/files/:fileId')
|
||||
->desc('Update File')
|
||||
->label('scope', 'files.write')
|
||||
->label('webhook', 'storage.files.update')
|
||||
->label('sdk.namespace', 'storage')
|
||||
->label('sdk.method', 'updateFile')
|
||||
->label('sdk.description', '/docs/references/storage/update-file.md')
|
||||
|
@ -543,7 +549,7 @@ $utopia->put('/v1/storage/files/:fileId')
|
|||
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
|
||||
//->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, $audit, $webhook) {
|
||||
$file = $projectDB->getDocument($fileId);
|
||||
|
||||
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
|
||||
|
@ -562,6 +568,15 @@ $utopia->put('/v1/storage/files/:fileId')
|
|||
throw new Exception('Failed saving file to DB', 500);
|
||||
}
|
||||
|
||||
$webhook
|
||||
->setParam('payload', $file->getArrayCopy())
|
||||
;
|
||||
|
||||
$audit
|
||||
->setParam('event', 'storage.files.update')
|
||||
->setParam('resource', 'storage/files/'.$file->getUid())
|
||||
;
|
||||
|
||||
$response->json($file->getArrayCopy());
|
||||
}
|
||||
);
|
||||
|
@ -569,12 +584,13 @@ $utopia->put('/v1/storage/files/:fileId')
|
|||
$utopia->delete('/v1/storage/files/:fileId')
|
||||
->desc('Delete File')
|
||||
->label('scope', 'files.write')
|
||||
->label('webhook', 'storage.files.delete')
|
||||
->label('sdk.namespace', 'storage')
|
||||
->label('sdk.method', 'deleteFile')
|
||||
->label('sdk.description', '/docs/references/storage/delete-file.md')
|
||||
->param('fileId', '', function () { return new UID(); }, 'File unique ID.')
|
||||
->action(
|
||||
function ($fileId) use ($response, $projectDB, $audit, $usage) {
|
||||
function ($fileId) use ($response, $projectDB, $webhook, $audit, $usage) {
|
||||
$file = $projectDB->getDocument($fileId);
|
||||
|
||||
if (empty($file->getUid()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
|
||||
|
@ -589,9 +605,13 @@ $utopia->delete('/v1/storage/files/:fileId')
|
|||
}
|
||||
}
|
||||
|
||||
$webhook
|
||||
->setParam('payload', $file->getArrayCopy())
|
||||
;
|
||||
|
||||
$audit
|
||||
->setParam('event', 'storage.delete')
|
||||
->setParam('resource', 'storage/file/'.$file->getUid())
|
||||
->setParam('event', 'storage.files.delete')
|
||||
->setParam('resource', 'storage/files/'.$file->getUid())
|
||||
;
|
||||
|
||||
$usage
|
||||
|
|
Loading…
Reference in a new issue