mirror of
https://github.com/appwrite/appwrite
synced 2026-05-14 20:48:45 +00:00
Merge branch '1.6.x' into fix-messaging-test-for-audits
This commit is contained in:
commit
4bfd132eee
6 changed files with 140 additions and 20 deletions
|
|
@ -17,6 +17,7 @@ use Appwrite\Event\Delete;
|
|||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Messaging;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Hooks\Hooks;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
|
|
@ -27,7 +28,9 @@ use Appwrite\Utopia\Database\Validator\CustomId;
|
|||
use Appwrite\Utopia\Database\Validator\Queries\Identities;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use libphonenumber\PhoneNumberUtil;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit as EventAudit;
|
||||
use Utopia\Config\Config;
|
||||
|
|
@ -2315,7 +2318,10 @@ App::post('/v1/account/tokens/phone')
|
|||
->inject('queueForEvents')
|
||||
->inject('queueForMessaging')
|
||||
->inject('locale')
|
||||
->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale) {
|
||||
->inject('timelimit')
|
||||
->inject('queueForUsage')
|
||||
->inject('plan')
|
||||
->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, Usage $queueForUsage, array $plan) {
|
||||
if (empty(System::getEnv('_APP_SMS_PROVIDER'))) {
|
||||
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
|
||||
}
|
||||
|
|
@ -2452,6 +2458,27 @@ App::post('/v1/account/tokens/phone')
|
|||
->setMessage($messageDoc)
|
||||
->setRecipients([$phone])
|
||||
->setProviderType(MESSAGE_TYPE_SMS);
|
||||
|
||||
if (isset($plan['authPhone'])) {
|
||||
$timelimit = $timelimit('organization:{organizationId}', $plan['authPhone'], 30 * 24 * 60 * 60); // 30 days
|
||||
$timelimit
|
||||
->setParam('{organizationId}', $project->getAttribute('teamId'));
|
||||
|
||||
$abuse = new Abuse($timelimit);
|
||||
if ($abuse->check() && System::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||
$helper = PhoneNumberUtil::getInstance();
|
||||
$countryCode = $helper->parse($phone)->getCountryCode();
|
||||
|
||||
if (!empty($countryCode)) {
|
||||
$queueForUsage
|
||||
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
|
||||
}
|
||||
}
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
// Set to unhashed secret for events and server responses
|
||||
|
|
@ -3465,7 +3492,10 @@ App::post('/v1/account/verification/phone')
|
|||
->inject('queueForMessaging')
|
||||
->inject('project')
|
||||
->inject('locale')
|
||||
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale) {
|
||||
->inject('timelimit')
|
||||
->inject('queueForUsage')
|
||||
->inject('plan')
|
||||
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, Usage $queueForUsage, array $plan) {
|
||||
if (empty(System::getEnv('_APP_SMS_PROVIDER'))) {
|
||||
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
|
||||
}
|
||||
|
|
@ -3548,6 +3578,27 @@ App::post('/v1/account/verification/phone')
|
|||
->setMessage($messageDoc)
|
||||
->setRecipients([$user->getAttribute('phone')])
|
||||
->setProviderType(MESSAGE_TYPE_SMS);
|
||||
|
||||
if (isset($plan['authPhone'])) {
|
||||
$timelimit = $timelimit('organization:{organizationId}', $plan['authPhone'], 30 * 24 * 60 * 60); // 30 days
|
||||
$timelimit
|
||||
->setParam('{organizationId}', $project->getAttribute('teamId'));
|
||||
|
||||
$abuse = new Abuse($timelimit);
|
||||
if ($abuse->check() && System::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||
$helper = PhoneNumberUtil::getInstance();
|
||||
$countryCode = $helper->parse($phone)->getCountryCode();
|
||||
|
||||
if (!empty($countryCode)) {
|
||||
$queueForUsage
|
||||
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
|
||||
}
|
||||
}
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
// Set to unhashed secret for events and server responses
|
||||
|
|
@ -4026,7 +4077,10 @@ App::post('/v1/account/mfa/challenge')
|
|||
->inject('queueForEvents')
|
||||
->inject('queueForMessaging')
|
||||
->inject('queueForMails')
|
||||
->action(function (string $factor, Response $response, Database $dbForProject, Document $user, Locale $locale, Document $project, Request $request, Event $queueForEvents, Messaging $queueForMessaging, Mail $queueForMails) {
|
||||
->inject('timelimit')
|
||||
->inject('queueForUsage')
|
||||
->inject('plan')
|
||||
->action(function (string $factor, Response $response, Database $dbForProject, Document $user, Locale $locale, Document $project, Request $request, Event $queueForEvents, Messaging $queueForMessaging, Mail $queueForMails, callable $timelimit, Usage $queueForUsage, array $plan) {
|
||||
|
||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM);
|
||||
$code = Auth::codeGenerator();
|
||||
|
|
@ -4074,6 +4128,7 @@ App::post('/v1/account/mfa/challenge')
|
|||
|
||||
$message = $message->render();
|
||||
|
||||
$phone = $user->getAttribute('phone');
|
||||
$queueForMessaging
|
||||
->setType(MESSAGE_SEND_TYPE_INTERNAL)
|
||||
->setMessage(new Document([
|
||||
|
|
@ -4082,8 +4137,29 @@ App::post('/v1/account/mfa/challenge')
|
|||
'content' => $code,
|
||||
],
|
||||
]))
|
||||
->setRecipients([$user->getAttribute('phone')])
|
||||
->setRecipients([$phone])
|
||||
->setProviderType(MESSAGE_TYPE_SMS);
|
||||
|
||||
if (isset($plan['authPhone'])) {
|
||||
$timelimit = $timelimit('organization:{organizationId}', $plan['authPhone'], 30 * 24 * 60 * 60); // 30 days
|
||||
$timelimit
|
||||
->setParam('{organizationId}', $project->getAttribute('teamId'));
|
||||
|
||||
$abuse = new Abuse($timelimit);
|
||||
if ($abuse->check() && System::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||
$helper = PhoneNumberUtil::getInstance();
|
||||
$countryCode = $helper->parse($phone)->getCountryCode();
|
||||
|
||||
if (!empty($countryCode)) {
|
||||
$queueForUsage
|
||||
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
|
||||
}
|
||||
}
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
}
|
||||
break;
|
||||
case Type::EMAIL:
|
||||
if (empty(System::getEnv('_APP_SMTP_HOST'))) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use Appwrite\Event\Delete;
|
|||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Messaging;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Platform\Workers\Deletes;
|
||||
|
|
@ -17,7 +18,9 @@ use Appwrite\Utopia\Database\Validator\Queries\Memberships;
|
|||
use Appwrite\Utopia\Database\Validator\Queries\Teams;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use libphonenumber\PhoneNumberUtil;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Config\Config;
|
||||
|
|
@ -423,7 +426,10 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
->inject('queueForMails')
|
||||
->inject('queueForMessaging')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents) {
|
||||
->inject('timelimit')
|
||||
->inject('queueForUsage')
|
||||
->inject('plan')
|
||||
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, Usage $queueForUsage, array $plan) {
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
|
||||
|
|
@ -691,6 +697,27 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
->setMessage($messageDoc)
|
||||
->setRecipients([$phone])
|
||||
->setProviderType('SMS');
|
||||
|
||||
if (isset($plan['authPhone'])) {
|
||||
$timelimit = $timelimit('organization:{organizationId}', $plan['authPhone'], 30 * 24 * 60 * 60); // 30 days
|
||||
$timelimit
|
||||
->setParam('{organizationId}', $project->getAttribute('teamId'));
|
||||
|
||||
$abuse = new Abuse($timelimit);
|
||||
if ($abuse->check() && System::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||
$helper = PhoneNumberUtil::getInstance();
|
||||
$countryCode = $helper->parse($phone)->getCountryCode();
|
||||
|
||||
if (!empty($countryCode)) {
|
||||
$queueForUsage
|
||||
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
|
||||
}
|
||||
}
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -506,6 +506,7 @@ App::init()
|
|||
->setMode($mode)
|
||||
->setUserAgent($request->getUserAgent(''))
|
||||
->setIP($request->getIP())
|
||||
->setHostname($request->getHostname())
|
||||
->setEvent($route->getLabel('audits.event', ''))
|
||||
->setProject($project)
|
||||
->setUser($user);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class Audit extends Event
|
|||
protected string $mode = '';
|
||||
protected string $userAgent = '';
|
||||
protected string $ip = '';
|
||||
protected string $hostname = '';
|
||||
|
||||
public function __construct(protected Connection $connection)
|
||||
{
|
||||
|
|
@ -113,6 +114,30 @@ class Audit extends Event
|
|||
return $this->ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hostname.
|
||||
*
|
||||
* @param string $hostname
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setHostname(string $hostname): self
|
||||
{
|
||||
$this->hostname = $hostname;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hostname.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHostname(): string
|
||||
{
|
||||
return $this->hostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the event and sends it to the audit worker.
|
||||
*
|
||||
|
|
@ -136,6 +161,7 @@ class Audit extends Event
|
|||
'ip' => $this->ip,
|
||||
'userAgent' => $this->userAgent,
|
||||
'event' => $this->event,
|
||||
'hostname' => $this->hostname
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class Messaging extends Event
|
|||
/**
|
||||
* Sets type for the build event.
|
||||
*
|
||||
* @param string $type Can be `MESSAGE_TYPE_INTERNAL` or `MESSAGE_TYPE_EXTERNAL`.
|
||||
* @param string $type Can be `MESSAGE_SEND_TYPE_INTERNAL` or `MESSAGE_SEND_TYPE_EXTERNAL`.
|
||||
* @return self
|
||||
*/
|
||||
public function setType(string $type): self
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ class Messaging extends Action
|
|||
$message = new Document($payload['message'] ?? []);
|
||||
$recipients = $payload['recipients'] ?? [];
|
||||
|
||||
$this->sendInternalSMSMessage($message, $project, $recipients, $queueForUsage, $log);
|
||||
$this->sendInternalSMSMessage($message, $project, $recipients, $log);
|
||||
break;
|
||||
case MESSAGE_SEND_TYPE_EXTERNAL:
|
||||
$message = $dbForProject->getDocument('messages', $payload['messageId']);
|
||||
|
|
@ -377,7 +377,7 @@ class Messaging extends Action
|
|||
}
|
||||
}
|
||||
|
||||
private function sendInternalSMSMessage(Document $message, Document $project, array $recipients, Usage $queueForUsage, Log $log): void
|
||||
private function sendInternalSMSMessage(Document $message, Document $project, array $recipients, Log $log): void
|
||||
{
|
||||
if (empty(System::getEnv('_APP_SMS_PROVIDER')) || empty(System::getEnv('_APP_SMS_FROM'))) {
|
||||
throw new \Exception('Skipped SMS processing. Missing "_APP_SMS_PROVIDER" or "_APP_SMS_FROM" environment variables.');
|
||||
|
|
@ -456,24 +456,14 @@ class Messaging extends Action
|
|||
$adapter->getMaxMessagesPerRequest()
|
||||
);
|
||||
|
||||
batch(\array_map(function ($batch) use ($message, $provider, $adapter, $project, $queueForUsage) {
|
||||
return function () use ($batch, $message, $provider, $adapter, $project, $queueForUsage) {
|
||||
batch(\array_map(function ($batch) use ($message, $provider, $adapter) {
|
||||
return function () use ($batch, $message, $provider, $adapter) {
|
||||
$message->setAttribute('to', $batch);
|
||||
|
||||
$data = $this->buildSmsMessage($message, $provider);
|
||||
|
||||
try {
|
||||
$adapter->send($data);
|
||||
|
||||
$countryCode = $adapter->getCountryCode($message['to'][0] ?? '');
|
||||
if (!empty($countryCode)) {
|
||||
$queueForUsage
|
||||
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
|
||||
}
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Failed sending to targets with error: ' . $th->getMessage());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue