2019-05-09 06:54:39 +00:00
< ? php
2020-03-25 04:34:06 +00:00
/**
* Init
2022-05-23 14:54:50 +00:00
*
2020-09-24 22:32:39 +00:00
* Initializes both Appwrite API entry point , queue workers , and CLI tasks .
2020-12-26 11:56:29 +00:00
* Set configuration , framework resources & app constants
2022-05-23 14:54:50 +00:00
*
2020-03-25 04:34:06 +00:00
*/
2022-05-23 14:54:50 +00:00
if ( \file_exists ( __DIR__ . '/../vendor/autoload.php' )) {
require_once __DIR__ . '/../vendor/autoload.php' ;
2019-07-31 20:35:42 +00:00
}
2019-05-09 06:54:39 +00:00
2023-11-22 08:32:36 +00:00
\ini_set ( 'memory_limit' , '512M' );
\ini_set ( 'display_errors' , 1 );
\ini_set ( 'display_startup_errors' , 1 );
\ini_set ( 'default_socket_timeout' , - 1 );
\error_reporting ( E_ALL );
2021-06-11 16:09:46 +00:00
2024-03-06 17:34:21 +00:00
use Ahc\Jwt\JWT ;
use Ahc\Jwt\JWTException ;
2020-06-30 18:08:02 +00:00
use Appwrite\Auth\Auth ;
2022-04-13 12:39:31 +00:00
use Appwrite\Event\Audit ;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Build ;
use Appwrite\Event\Certificate ;
2022-04-13 12:39:31 +00:00
use Appwrite\Event\Database as EventDatabase ;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Delete ;
2020-06-27 19:42:38 +00:00
use Appwrite\Event\Event ;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Func ;
2022-04-13 12:39:31 +00:00
use Appwrite\Event\Mail ;
2023-09-05 17:10:48 +00:00
use Appwrite\Event\Messaging ;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Migration ;
2024-11-04 15:05:54 +00:00
use Appwrite\Event\Realtime ;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Usage ;
2024-11-04 15:05:54 +00:00
use Appwrite\Event\Webhook ;
2024-03-06 17:34:21 +00:00
use Appwrite\Extend\Exception ;
2024-08-06 09:54:46 +00:00
use Appwrite\Functions\Specification ;
2024-03-06 17:34:21 +00:00
use Appwrite\GraphQL\Promises\Adapter\Swoole ;
2023-05-23 13:43:03 +00:00
use Appwrite\GraphQL\Schema ;
2024-03-06 17:34:21 +00:00
use Appwrite\Hooks\Hooks ;
2021-07-23 14:59:55 +00:00
use Appwrite\Network\Validator\Email ;
2023-05-23 13:43:03 +00:00
use Appwrite\Network\Validator\Origin ;
2020-05-12 22:00:00 +00:00
use Appwrite\OpenSSL\OpenSSL ;
2024-10-31 12:12:03 +00:00
use Appwrite\PubSub\Adapter\Redis as PubSub ;
2022-10-19 12:41:38 +00:00
use Appwrite\URL\URL as AppwriteURL ;
2024-09-04 02:16:18 +00:00
use Appwrite\Utopia\Request ;
2024-03-06 17:34:21 +00:00
use MaxMind\Db\Reader ;
use PHPMailer\PHPMailer\PHPMailer ;
use Swoole\Database\PDOProxy ;
2020-07-01 22:34:05 +00:00
use Utopia\App ;
2022-07-13 09:34:56 +00:00
use Utopia\Cache\Adapter\Redis as RedisCache ;
2024-03-06 17:34:21 +00:00
use Utopia\Cache\Adapter\Sharding ;
2022-07-13 09:34:56 +00:00
use Utopia\Cache\Cache ;
2024-03-06 17:34:21 +00:00
use Utopia\CLI\Console ;
2023-05-23 13:43:03 +00:00
use Utopia\Config\Config ;
2024-03-06 17:34:21 +00:00
use Utopia\Database\Adapter\MariaDB ;
use Utopia\Database\Adapter\MySQL ;
use Utopia\Database\Adapter\SQL ;
2021-08-21 15:09:08 +00:00
use Utopia\Database\Database ;
2023-05-23 13:43:03 +00:00
use Utopia\Database\Document ;
2024-03-06 17:34:21 +00:00
use Utopia\Database\Helpers\ID ;
2021-08-20 11:15:17 +00:00
use Utopia\Database\Query ;
2022-10-15 08:52:50 +00:00
use Utopia\Database\Validator\Authorization ;
2023-03-12 14:04:18 +00:00
use Utopia\Database\Validator\Datetime as DatetimeValidator ;
2022-10-15 08:52:50 +00:00
use Utopia\Database\Validator\Structure ;
2024-03-06 17:34:21 +00:00
use Utopia\Domains\Validator\PublicDomain ;
2023-05-23 13:43:03 +00:00
use Utopia\DSN\DSN ;
2024-03-06 17:34:21 +00:00
use Utopia\Locale\Locale ;
2024-07-03 13:29:35 +00:00
use Utopia\Logger\Adapter\AppSignal ;
use Utopia\Logger\Adapter\LogOwl ;
use Utopia\Logger\Adapter\Raygun ;
use Utopia\Logger\Adapter\Sentry ;
2024-03-06 17:34:21 +00:00
use Utopia\Logger\Log ;
use Utopia\Logger\Logger ;
use Utopia\Pools\Group ;
use Utopia\Pools\Pool ;
use Utopia\Queue ;
use Utopia\Queue\Connection ;
2022-10-15 08:52:50 +00:00
use Utopia\Registry\Registry ;
2022-02-17 09:13:39 +00:00
use Utopia\Storage\Device ;
2022-05-10 11:15:56 +00:00
use Utopia\Storage\Device\Backblaze ;
2022-02-08 15:40:56 +00:00
use Utopia\Storage\Device\DOSpaces ;
2023-05-23 13:43:03 +00:00
use Utopia\Storage\Device\Linode ;
2021-12-13 07:34:15 +00:00
use Utopia\Storage\Device\Local ;
use Utopia\Storage\Device\S3 ;
2022-03-18 17:17:43 +00:00
use Utopia\Storage\Device\Wasabi ;
2022-11-17 17:43:59 +00:00
use Utopia\Storage\Storage ;
2024-04-01 11:08:46 +00:00
use Utopia\System\System ;
2024-01-03 19:25:54 +00:00
use Utopia\Validator\Hostname ;
2023-05-23 13:43:03 +00:00
use Utopia\Validator\IP ;
2024-03-06 17:34:21 +00:00
use Utopia\Validator\Range ;
2023-05-23 13:43:03 +00:00
use Utopia\Validator\URL ;
use Utopia\Validator\WhiteList ;
2024-03-06 17:34:21 +00:00
use Utopia\VCS\Adapter\Git\GitHub as VcsGitHub ;
2019-05-09 06:54:39 +00:00
2019-10-01 04:57:41 +00:00
const APP_NAME = 'Appwrite' ;
const APP_DOMAIN = 'appwrite.io' ;
2020-03-01 22:10:52 +00:00
const APP_EMAIL_TEAM = 'team@localhost.test' ; // Default email address
2021-02-18 16:48:11 +00:00
const APP_EMAIL_SECURITY = '' ; // Default security email address
2022-05-23 14:54:50 +00:00
const APP_USERAGENT = APP_NAME . '-Server v%s. Please report abuse at %s' ;
2020-11-18 22:08:45 +00:00
const APP_MODE_DEFAULT = 'default' ;
2019-10-01 04:57:41 +00:00
const APP_MODE_ADMIN = 'admin' ;
2020-07-19 14:43:34 +00:00
const APP_PAGING_LIMIT = 12 ;
2021-05-09 18:37:47 +00:00
const APP_LIMIT_COUNT = 5000 ;
2024-01-11 02:54:44 +00:00
const APP_LIMIT_USERS = 10_000 ;
2022-12-16 10:37:49 +00:00
const APP_LIMIT_USER_PASSWORD_HISTORY = 20 ;
2023-05-23 13:43:03 +00:00
const APP_LIMIT_USER_SESSIONS_MAX = 100 ;
const APP_LIMIT_USER_SESSIONS_DEFAULT = 10 ;
2024-01-11 02:54:44 +00:00
const APP_LIMIT_ANTIVIRUS = 20_000_000 ; //20MB
const APP_LIMIT_ENCRYPTION = 20_000_000 ; //20MB
const APP_LIMIT_COMPRESSION = 20_000_000 ; //20MB
2022-05-01 07:54:58 +00:00
const APP_LIMIT_ARRAY_PARAMS_SIZE = 100 ; // Default maximum of how many elements can there be in API parameter that expects array value
2024-01-28 10:51:05 +00:00
const APP_LIMIT_ARRAY_LABELS_SIZE = 1000 ; // Default maximum of how many labels elements can there be in API parameter that expects array value
2022-06-22 09:08:11 +00:00
const APP_LIMIT_ARRAY_ELEMENT_SIZE = 4096 ; // Default maximum length of element in array parameter represented by maximum URL length.
2022-05-30 12:01:39 +00:00
const APP_LIMIT_SUBQUERY = 1000 ;
2024-01-11 02:54:44 +00:00
const APP_LIMIT_SUBSCRIBERS_SUBQUERY = 1_000_000 ;
2022-08-30 23:34:17 +00:00
const APP_LIMIT_WRITE_RATE_DEFAULT = 60 ; // Default maximum write rate per rate period
const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60 ; // Default maximum write rate period in seconds
2023-05-23 13:43:03 +00:00
const APP_LIMIT_LIST_DEFAULT = 25 ; // Default maximum number of items to return in list API calls
2024-07-08 01:03:52 +00:00
const APP_KEY_ACCESS = 24 * 60 * 60 ; // 24 hours
const APP_USER_ACCESS = 24 * 60 * 60 ; // 24 hours
2024-07-08 01:02:58 +00:00
const APP_PROJECT_ACCESS = 24 * 60 * 60 ; // 24 hours
2022-08-31 13:11:23 +00:00
const APP_CACHE_UPDATE = 24 * 60 * 60 ; // 24 hours
2024-08-27 11:58:19 +00:00
const APP_CACHE_BUSTER = 4318 ;
2024-11-22 22:47:02 +00:00
const APP_VERSION_STABLE = '1.6.1' ;
2021-08-16 22:05:52 +00:00
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email' ;
2021-09-10 20:12:22 +00:00
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum' ;
2021-08-16 22:05:52 +00:00
const APP_DATABASE_ATTRIBUTE_IP = 'ip' ;
2022-07-25 08:53:41 +00:00
const APP_DATABASE_ATTRIBUTE_DATETIME = 'datetime' ;
2021-08-16 22:05:52 +00:00
const APP_DATABASE_ATTRIBUTE_URL = 'url' ;
const APP_DATABASE_ATTRIBUTE_INT_RANGE = 'intRange' ;
const APP_DATABASE_ATTRIBUTE_FLOAT_RANGE = 'floatRange' ;
2024-01-11 02:54:44 +00:00
const APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH = 1_073_741_824 ; // 2^32 bits / 4 bits per char
const APP_DATABASE_TIMEOUT_MILLISECONDS = 15_000 ;
2024-10-16 08:35:32 +00:00
const APP_DATABASE_QUERY_MAX_VALUES = 500 ;
2020-02-19 12:41:23 +00:00
const APP_STORAGE_UPLOADS = '/storage/uploads' ;
2020-07-14 21:20:46 +00:00
const APP_STORAGE_FUNCTIONS = '/storage/functions' ;
2021-12-08 15:08:53 +00:00
const APP_STORAGE_BUILDS = '/storage/builds' ;
2020-02-19 12:41:23 +00:00
const APP_STORAGE_CACHE = '/storage/cache' ;
const APP_STORAGE_CERTIFICATES = '/storage/certificates' ;
2020-02-25 10:04:12 +00:00
const APP_STORAGE_CONFIG = '/storage/config' ;
2022-01-31 08:37:45 +00:00
const APP_STORAGE_READ_BUFFER = 20 * ( 1000 * 1000 ); //20MB other names `APP_STORAGE_MEMORY_LIMIT`, `APP_STORAGE_MEMORY_BUFFER`, `APP_STORAGE_READ_LIMIT`, `APP_STORAGE_BUFFER_LIMIT`
2021-12-11 20:17:33 +00:00
const APP_SOCIAL_TWITTER = 'https://twitter.com/appwrite' ;
const APP_SOCIAL_TWITTER_HANDLE = 'appwrite' ;
2020-02-20 20:43:06 +00:00
const APP_SOCIAL_FACEBOOK = 'https://www.facebook.com/appwrite.io' ;
const APP_SOCIAL_LINKEDIN = 'https://www.linkedin.com/company/appwrite' ;
const APP_SOCIAL_INSTAGRAM = 'https://www.instagram.com/appwrite.io' ;
const APP_SOCIAL_GITHUB = 'https://github.com/appwrite' ;
2020-07-20 03:59:04 +00:00
const APP_SOCIAL_DISCORD = 'https://appwrite.io/discord' ;
2021-04-10 16:14:15 +00:00
const APP_SOCIAL_DISCORD_CHANNEL = '564160730845151244' ;
2020-05-17 15:57:42 +00:00
const APP_SOCIAL_DEV = 'https://dev.to/appwrite' ;
2022-05-23 14:54:50 +00:00
const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite' ;
2021-12-11 00:17:28 +00:00
const APP_SOCIAL_YOUTUBE = 'https://www.youtube.com/c/appwrite?sub_confirmation=1' ;
2023-08-16 18:08:24 +00:00
const APP_HOSTNAME_INTERNAL = 'appwrite' ;
2024-10-23 13:22:37 +00:00
const APP_FUNCTION_SPECIFICATION_DEFAULT = Specification :: S_1VCPU_512MB ;
2024-08-20 04:23:11 +00:00
const APP_FUNCTION_CPUS_DEFAULT = 0.5 ;
const APP_FUNCTION_MEMORY_DEFAULT = 512 ;
2024-08-28 09:35:16 +00:00
const APP_PLATFORM_SERVER = 'server' ;
const APP_PLATFORM_CLIENT = 'client' ;
const APP_PLATFORM_CONSOLE = 'console' ;
2024-02-20 12:06:35 +00:00
2022-01-21 17:32:27 +00:00
// Database Reconnect
const DATABASE_RECONNECT_SLEEP = 2 ;
const DATABASE_RECONNECT_MAX_ATTEMPTS = 10 ;
2024-02-20 12:06:35 +00:00
2021-08-08 23:42:08 +00:00
// Database Worker Types
const DATABASE_TYPE_CREATE_ATTRIBUTE = 'createAttribute' ;
const DATABASE_TYPE_CREATE_INDEX = 'createIndex' ;
const DATABASE_TYPE_DELETE_ATTRIBUTE = 'deleteAttribute' ;
const DATABASE_TYPE_DELETE_INDEX = 'deleteIndex' ;
2023-10-16 23:18:51 +00:00
const DATABASE_TYPE_DELETE_COLLECTION = 'deleteCollection' ;
const DATABASE_TYPE_DELETE_DATABASE = 'deleteDatabase' ;
2024-02-20 12:06:35 +00:00
2022-01-23 23:01:42 +00:00
// Build Worker Types
2022-01-26 13:09:32 +00:00
const BUILD_TYPE_DEPLOYMENT = 'deployment' ;
2022-01-23 23:01:42 +00:00
const BUILD_TYPE_RETRY = 'retry' ;
2024-02-20 12:06:35 +00:00
2020-12-18 14:05:15 +00:00
// Deletion Types
2022-06-22 10:51:49 +00:00
const DELETE_TYPE_DATABASES = 'databases' ;
2020-12-18 14:05:15 +00:00
const DELETE_TYPE_DOCUMENT = 'document' ;
2021-10-26 00:14:55 +00:00
const DELETE_TYPE_COLLECTIONS = 'collections' ;
const DELETE_TYPE_PROJECTS = 'projects' ;
const DELETE_TYPE_FUNCTIONS = 'functions' ;
2022-01-27 23:36:30 +00:00
const DELETE_TYPE_DEPLOYMENTS = 'deployments' ;
2021-10-26 00:14:55 +00:00
const DELETE_TYPE_USERS = 'users' ;
2024-06-27 22:27:04 +00:00
const DELETE_TYPE_TEAM_PROJECTS = 'teams_projects' ;
2020-12-27 17:57:35 +00:00
const DELETE_TYPE_EXECUTIONS = 'executions' ;
2020-12-18 14:05:15 +00:00
const DELETE_TYPE_AUDIT = 'audit' ;
const DELETE_TYPE_ABUSE = 'abuse' ;
2021-09-08 06:55:48 +00:00
const DELETE_TYPE_USAGE = 'usage' ;
2021-06-16 09:35:37 +00:00
const DELETE_TYPE_REALTIME = 'realtime' ;
2021-11-07 05:54:28 +00:00
const DELETE_TYPE_BUCKETS = 'buckets' ;
2023-07-30 19:10:25 +00:00
const DELETE_TYPE_INSTALLATIONS = 'installations' ;
2023-03-10 07:42:52 +00:00
const DELETE_TYPE_RULES = 'rules' ;
2022-06-02 10:20:03 +00:00
const DELETE_TYPE_SESSIONS = 'sessions' ;
2022-08-15 09:05:41 +00:00
const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp' ;
const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource' ;
2022-11-16 12:51:43 +00:00
const DELETE_TYPE_SCHEDULES = 'schedules' ;
2023-10-25 17:33:23 +00:00
const DELETE_TYPE_TOPIC = 'topic' ;
2024-01-04 21:44:33 +00:00
const DELETE_TYPE_TARGET = 'target' ;
2024-01-19 04:23:44 +00:00
const DELETE_TYPE_EXPIRED_TARGETS = 'invalid_targets' ;
2024-02-02 14:03:31 +00:00
const DELETE_TYPE_SESSION_TARGETS = 'session_targets' ;
2024-02-20 12:06:35 +00:00
// Message types
const MESSAGE_SEND_TYPE_INTERNAL = 'internal' ;
const MESSAGE_SEND_TYPE_EXTERNAL = 'external' ;
2021-07-27 20:31:19 +00:00
// Mail Types
const MAIL_TYPE_VERIFICATION = 'verification' ;
2021-08-30 10:44:52 +00:00
const MAIL_TYPE_MAGIC_SESSION = 'magicSession' ;
2021-07-27 20:31:19 +00:00
const MAIL_TYPE_RECOVERY = 'recovery' ;
const MAIL_TYPE_INVITATION = 'invitation' ;
2022-04-13 12:26:07 +00:00
const MAIL_TYPE_CERTIFICATE = 'certificate' ;
2021-03-28 21:22:12 +00:00
// Auth Types
const APP_AUTH_TYPE_SESSION = 'Session' ;
const APP_AUTH_TYPE_JWT = 'JWT' ;
const APP_AUTH_TYPE_KEY = 'Key' ;
const APP_AUTH_TYPE_ADMIN = 'Admin' ;
2021-09-30 08:41:29 +00:00
// Response related
2024-05-03 12:31:15 +00:00
const MAX_OUTPUT_CHUNK_SIZE = 10 * 1024 * 1024 ; // 10MB
2023-07-30 07:17:23 +00:00
// Function headers
2023-08-20 11:43:06 +00:00
const FUNCTION_ALLOWLIST_HEADERS_REQUEST = [ 'content-type' , 'agent' , 'content-length' , 'host' ];
2023-08-11 13:34:57 +00:00
const FUNCTION_ALLOWLIST_HEADERS_RESPONSE = [ 'content-type' , 'content-length' ];
2023-11-29 04:05:37 +00:00
// Message types
const MESSAGE_TYPE_EMAIL = 'email' ;
const MESSAGE_TYPE_SMS = 'sms' ;
const MESSAGE_TYPE_PUSH = 'push' ;
2024-05-14 11:58:31 +00:00
// API key types
const API_KEY_STANDARD = 'standard' ;
const API_KEY_DYNAMIC = 'dynamic' ;
2023-05-23 13:43:03 +00:00
// Usage metrics
const METRIC_TEAMS = 'teams' ;
const METRIC_USERS = 'users' ;
2024-09-05 17:11:39 +00:00
2024-09-09 13:05:11 +00:00
const METRIC_AUTH_METHOD_PHONE = 'auth.method.phone' ;
2024-09-09 12:54:32 +00:00
const METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE = METRIC_AUTH_METHOD_PHONE . '.{countryCode}' ;
2024-09-20 16:30:05 +00:00
const METRIC_MESSAGES = 'messages' ;
const METRIC_MESSAGES_SENT = METRIC_MESSAGES . '.sent' ;
const METRIC_MESSAGES_FAILED = METRIC_MESSAGES . '.failed' ;
const METRIC_MESSAGES_TYPE = METRIC_MESSAGES . '.{type}' ;
const METRIC_MESSAGES_TYPE_SENT = METRIC_MESSAGES . '.{type}.sent' ;
const METRIC_MESSAGES_TYPE_FAILED = METRIC_MESSAGES . '.{type}.failed' ;
const METRIC_MESSAGES_TYPE_PROVIDER = METRIC_MESSAGES . '.{type}.{provider}' ;
const METRIC_MESSAGES_TYPE_PROVIDER_SENT = METRIC_MESSAGES . '.{type}.{provider}.sent' ;
const METRIC_MESSAGES_TYPE_PROVIDER_FAILED = METRIC_MESSAGES . '.{type}.{provider}.failed' ;
2023-05-23 13:43:03 +00:00
const METRIC_SESSIONS = 'sessions' ;
const METRIC_DATABASES = 'databases' ;
const METRIC_COLLECTIONS = 'collections' ;
2024-09-23 15:07:54 +00:00
const METRIC_DATABASES_STORAGE = 'databases.storage' ;
2023-05-23 13:43:03 +00:00
const METRIC_DATABASE_ID_COLLECTIONS = '{databaseInternalId}.collections' ;
2024-09-23 15:07:54 +00:00
const METRIC_DATABASE_ID_STORAGE = '{databaseInternalId}.databases.storage' ;
2023-05-23 13:43:03 +00:00
const METRIC_DOCUMENTS = 'documents' ;
const METRIC_DATABASE_ID_DOCUMENTS = '{databaseInternalId}.documents' ;
const METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS = '{databaseInternalId}.{collectionInternalId}.documents' ;
2024-09-23 15:07:54 +00:00
const METRIC_DATABASE_ID_COLLECTION_ID_STORAGE = '{databaseInternalId}.{collectionInternalId}.databases.storage' ;
2023-05-23 13:43:03 +00:00
const METRIC_BUCKETS = 'buckets' ;
const METRIC_FILES = 'files' ;
const METRIC_FILES_STORAGE = 'files.storage' ;
const METRIC_BUCKET_ID_FILES = '{bucketInternalId}.files' ;
const METRIC_BUCKET_ID_FILES_STORAGE = '{bucketInternalId}.files.storage' ;
const METRIC_FUNCTIONS = 'functions' ;
const METRIC_DEPLOYMENTS = 'deployments' ;
const METRIC_DEPLOYMENTS_STORAGE = 'deployments.storage' ;
const METRIC_BUILDS = 'builds' ;
2024-05-28 12:59:28 +00:00
const METRIC_BUILDS_SUCCESS = 'builds.success' ;
const METRIC_BUILDS_FAILED = 'builds.failed' ;
2023-05-23 13:43:03 +00:00
const METRIC_BUILDS_STORAGE = 'builds.storage' ;
const METRIC_BUILDS_COMPUTE = 'builds.compute' ;
2024-05-28 12:59:28 +00:00
const METRIC_BUILDS_COMPUTE_SUCCESS = 'builds.compute.success' ;
const METRIC_BUILDS_COMPUTE_FAILED = 'builds.compute.failed' ;
2024-07-12 10:02:32 +00:00
const METRIC_BUILDS_MB_SECONDS = 'builds.mbSeconds' ;
2023-05-23 13:43:03 +00:00
const METRIC_FUNCTION_ID_BUILDS = '{functionInternalId}.builds' ;
2024-05-28 12:59:28 +00:00
const METRIC_FUNCTION_ID_BUILDS_SUCCESS = '{functionInternalId}.builds.success' ;
const METRIC_FUNCTION_ID_BUILDS_FAILED = '{functionInternalId}.builds.failed' ;
2023-05-23 13:43:03 +00:00
const METRIC_FUNCTION_ID_BUILDS_STORAGE = '{functionInternalId}.builds.storage' ;
const METRIC_FUNCTION_ID_BUILDS_COMPUTE = '{functionInternalId}.builds.compute' ;
2024-05-28 12:59:28 +00:00
const METRIC_FUNCTION_ID_BUILDS_COMPUTE_SUCCESS = '{functionInternalId}.builds.compute.success' ;
const METRIC_FUNCTION_ID_BUILDS_COMPUTE_FAILED = '{functionInternalId}.builds.compute.failed' ;
2023-05-23 13:43:03 +00:00
const METRIC_FUNCTION_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments' ;
const METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage' ;
2024-07-12 10:02:32 +00:00
const METRIC_FUNCTION_ID_BUILDS_MB_SECONDS = '{functionInternalId}.builds.mbSeconds' ;
2023-05-23 13:43:03 +00:00
const METRIC_EXECUTIONS = 'executions' ;
const METRIC_EXECUTIONS_COMPUTE = 'executions.compute' ;
2024-07-12 10:02:32 +00:00
const METRIC_EXECUTIONS_MB_SECONDS = 'executions.mbSeconds' ;
2023-05-23 13:43:03 +00:00
const METRIC_FUNCTION_ID_EXECUTIONS = '{functionInternalId}.executions' ;
const METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE = '{functionInternalId}.executions.compute' ;
2024-07-12 10:02:32 +00:00
const METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS = '{functionInternalId}.executions.mbSeconds' ;
2023-05-23 13:43:03 +00:00
const METRIC_NETWORK_REQUESTS = 'network.requests' ;
const METRIC_NETWORK_INBOUND = 'network.inbound' ;
const METRIC_NETWORK_OUTBOUND = 'network.outbound' ;
2019-05-09 06:54:39 +00:00
2024-10-29 15:07:12 +00:00
// Resource types
const RESOURCE_TYPE_PROJECTS = 'projects' ;
const RESOURCE_TYPE_FUNCTIONS = 'functions' ;
const RESOURCE_TYPE_DATABASES = 'databases' ;
const RESOURCE_TYPE_BUCKETS = 'buckets' ;
const RESOURCE_TYPE_PROVIDERS = 'providers' ;
const RESOURCE_TYPE_TOPICS = 'topics' ;
const RESOURCE_TYPE_SUBSCRIBERS = 'subscribers' ;
const RESOURCE_TYPE_MESSAGES = 'messages' ;
2019-10-01 04:57:41 +00:00
$register = new Registry ();
2020-06-19 00:04:09 +00:00
2024-04-01 11:02:47 +00:00
App :: setMode ( System :: getEnv ( '_APP_ENV' , App :: MODE_TYPE_PRODUCTION ));
2019-05-09 06:54:39 +00:00
2024-01-05 12:24:20 +00:00
if ( ! App :: isProduction ()) {
2024-01-08 20:11:48 +00:00
// Allow specific domains to skip public domain validation in dev environment
// Useful for existing tests involving webhooks
2024-01-04 11:07:15 +00:00
PublicDomain :: allow ([ 'request-catcher' ]);
}
2019-05-09 06:54:39 +00:00
2019-10-01 04:57:41 +00:00
/*
2019-05-09 06:54:39 +00:00
* ENV vars
*/
2022-05-23 14:54:50 +00:00
Config :: load ( 'events' , __DIR__ . '/config/events.php' );
Config :: load ( 'auth' , __DIR__ . '/config/auth.php' );
2024-03-04 22:12:54 +00:00
Config :: load ( 'apis' , __DIR__ . '/config/apis.php' ); // List of APIs
2022-05-23 14:54:50 +00:00
Config :: load ( 'errors' , __DIR__ . '/config/errors.php' );
2023-10-25 17:33:23 +00:00
Config :: load ( 'oAuthProviders' , __DIR__ . '/config/oAuthProviders.php' );
2022-05-23 14:54:50 +00:00
Config :: load ( 'platforms' , __DIR__ . '/config/platforms.php' );
Config :: load ( 'collections' , __DIR__ . '/config/collections.php' );
Config :: load ( 'runtimes' , __DIR__ . '/config/runtimes.php' );
2023-10-01 18:30:52 +00:00
Config :: load ( 'runtimes-v2' , __DIR__ . '/config/runtimes-v2.php' );
2023-10-25 07:39:59 +00:00
Config :: load ( 'usage' , __DIR__ . '/config/usage.php' );
2022-05-23 14:54:50 +00:00
Config :: load ( 'roles' , __DIR__ . '/config/roles.php' ); // User roles and scopes
Config :: load ( 'scopes' , __DIR__ . '/config/scopes.php' ); // User roles and scopes
Config :: load ( 'services' , __DIR__ . '/config/services.php' ); // List of services
Config :: load ( 'variables' , __DIR__ . '/config/variables.php' ); // List of env variables
2022-09-30 12:22:11 +00:00
Config :: load ( 'regions' , __DIR__ . '/config/regions.php' ); // List of available regions
2022-05-23 14:54:50 +00:00
Config :: load ( 'avatar-browsers' , __DIR__ . '/config/avatars/browsers.php' );
Config :: load ( 'avatar-credit-cards' , __DIR__ . '/config/avatars/credit-cards.php' );
Config :: load ( 'avatar-flags' , __DIR__ . '/config/avatars/flags.php' );
Config :: load ( 'locale-codes' , __DIR__ . '/config/locale/codes.php' );
Config :: load ( 'locale-currencies' , __DIR__ . '/config/locale/currencies.php' );
Config :: load ( 'locale-eu' , __DIR__ . '/config/locale/eu.php' );
Config :: load ( 'locale-languages' , __DIR__ . '/config/locale/languages.php' );
Config :: load ( 'locale-phones' , __DIR__ . '/config/locale/phones.php' );
Config :: load ( 'locale-countries' , __DIR__ . '/config/locale/countries.php' );
Config :: load ( 'locale-continents' , __DIR__ . '/config/locale/continents.php' );
2023-03-09 13:44:23 +00:00
Config :: load ( 'locale-templates' , __DIR__ . '/config/locale/templates.php' );
2022-05-23 14:54:50 +00:00
Config :: load ( 'storage-logos' , __DIR__ . '/config/storage/logos.php' );
Config :: load ( 'storage-mimes' , __DIR__ . '/config/storage/mimes.php' );
Config :: load ( 'storage-inputs' , __DIR__ . '/config/storage/inputs.php' );
Config :: load ( 'storage-outputs' , __DIR__ . '/config/storage/outputs.php' );
2024-07-31 11:27:32 +00:00
Config :: load ( 'runtime-specifications' , __DIR__ . '/config/runtimes/specifications.php' );
2024-07-29 20:55:18 +00:00
Config :: load ( 'function-templates' , __DIR__ . '/config/function-templates.php' );
2022-05-23 14:54:50 +00:00
2021-08-27 17:12:16 +00:00
/**
* New DB Filters
*/
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'casting' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2022-04-21 13:14:01 +00:00
return json_encode ([ 'value' => $value ], JSON_PRESERVE_ZERO_FRACTION );
2021-08-27 17:12:16 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2021-08-27 23:42:53 +00:00
if ( is_null ( $value )) {
2024-03-06 17:34:21 +00:00
return ;
2021-08-27 23:42:53 +00:00
}
2022-05-30 12:01:39 +00:00
2021-08-27 20:27:48 +00:00
return json_decode ( $value , true )[ 'value' ];
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'enum' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $attribute ) {
2021-09-10 20:14:12 +00:00
if ( $attribute -> isSet ( 'elements' )) {
$attribute -> removeAttribute ( 'elements' );
}
2022-05-30 12:01:39 +00:00
2021-09-10 20:14:12 +00:00
return $value ;
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $attribute ) {
2023-08-22 03:25:55 +00:00
$formatOptions = \json_decode ( $attribute -> getAttribute ( 'formatOptions' , '[]' ), true );
2021-09-10 20:14:12 +00:00
if ( isset ( $formatOptions [ 'elements' ])) {
$attribute -> setAttribute ( 'elements' , $formatOptions [ 'elements' ]);
}
2022-05-30 12:01:39 +00:00
2021-09-10 20:14:12 +00:00
return $value ;
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'range' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $attribute ) {
2021-08-27 20:27:48 +00:00
if ( $attribute -> isSet ( 'min' )) {
$attribute -> removeAttribute ( 'min' );
}
if ( $attribute -> isSet ( 'max' )) {
$attribute -> removeAttribute ( 'max' );
}
2022-05-30 12:01:39 +00:00
2021-08-27 20:27:48 +00:00
return $value ;
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $attribute ) {
2021-12-08 17:49:44 +00:00
$formatOptions = json_decode ( $attribute -> getAttribute ( 'formatOptions' , '[]' ), true );
2021-08-27 20:27:48 +00:00
if ( isset ( $formatOptions [ 'min' ]) || isset ( $formatOptions [ 'max' ])) {
$attribute
-> setAttribute ( 'min' , $formatOptions [ 'min' ])
2024-05-28 12:59:28 +00:00
-> setAttribute ( 'max' , $formatOptions [ 'max' ]);
2021-08-27 20:27:48 +00:00
}
2022-05-30 12:01:39 +00:00
2021-08-27 20:27:48 +00:00
return $value ;
2021-08-27 17:12:16 +00:00
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'subQueryAttributes' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2021-08-20 11:15:17 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $document , Database $database ) {
2023-03-25 03:28:07 +00:00
$attributes = $database -> find ( 'attributes' , [
Query :: equal ( 'collectionInternalId' , [ $document -> getInternalId ()]),
Query :: equal ( 'databaseInternalId' , [ $document -> getAttribute ( 'databaseInternalId' )]),
Query :: limit ( $database -> getLimitForAttributes ()),
]);
foreach ( $attributes as $attribute ) {
if ( $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP ) {
$options = $attribute -> getAttribute ( 'options' );
foreach ( $options as $key => $value ) {
$attribute -> setAttribute ( $key , $value );
}
$attribute -> removeAttribute ( 'options' );
}
}
return $attributes ;
2021-08-20 11:15:17 +00:00
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'subQueryIndexes' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2021-08-22 15:00:00 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $document , Database $database ) {
2021-08-22 15:00:00 +00:00
return $database
-> find ( 'indexes' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'collectionInternalId' , [ $document -> getInternalId ()]),
Query :: equal ( 'databaseInternalId' , [ $document -> getAttribute ( 'databaseInternalId' )]),
2023-08-22 03:25:55 +00:00
Query :: limit ( $database -> getLimitForIndexes ()),
2022-08-11 23:53:52 +00:00
]);
2021-08-22 15:00:00 +00:00
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'subQueryPlatforms' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2021-08-30 07:33:45 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $document , Database $database ) {
2021-08-30 07:33:45 +00:00
return $database
2021-09-01 08:43:35 +00:00
-> find ( 'platforms' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'projectInternalId' , [ $document -> getInternalId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY ),
]);
2021-08-30 14:24:50 +00:00
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'subQueryKeys' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2021-08-30 14:24:50 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $document , Database $database ) {
2021-08-30 14:24:50 +00:00
return $database
2021-09-01 08:43:35 +00:00
-> find ( 'keys' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'projectInternalId' , [ $document -> getInternalId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY ),
]);
2021-08-30 14:24:50 +00:00
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'subQueryWebhooks' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2021-08-30 14:24:50 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $document , Database $database ) {
2021-08-30 14:24:50 +00:00
return $database
2021-09-01 08:43:35 +00:00
-> find ( 'webhooks' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'projectInternalId' , [ $document -> getInternalId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY ),
]);
2021-08-22 15:00:00 +00:00
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'subQuerySessions' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2022-04-04 09:59:32 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $document , Database $database ) {
2022-06-01 17:13:15 +00:00
return Authorization :: skip ( fn () => $database -> find ( 'sessions' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'userInternalId' , [ $document -> getInternalId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY ),
]));
2022-04-04 09:59:32 +00:00
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'subQueryTokens' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2022-04-27 11:06:53 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $document , Database $database ) {
2024-03-06 17:34:21 +00:00
return Authorization :: skip ( fn () => $database
2022-04-27 11:06:53 +00:00
-> find ( 'tokens' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'userInternalId' , [ $document -> getInternalId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY ),
]));
2022-05-08 14:39:24 +00:00
}
);
2022-05-30 12:01:39 +00:00
2023-06-22 13:35:49 +00:00
Database :: addFilter (
'subQueryChallenges' ,
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2023-06-22 13:35:49 +00:00
},
function ( mixed $value , Document $document , Database $database ) {
2024-03-06 17:34:21 +00:00
return Authorization :: skip ( fn () => $database
2023-06-22 13:35:49 +00:00
-> find ( 'challenges' , [
Query :: equal ( 'userInternalId' , [ $document -> getInternalId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY ),
]));
}
);
2024-02-29 20:59:49 +00:00
Database :: addFilter (
'subQueryAuthenticators' ,
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2024-02-29 20:59:49 +00:00
},
function ( mixed $value , Document $document , Database $database ) {
2024-03-06 17:34:21 +00:00
return Authorization :: skip ( fn () => $database
2024-02-29 20:59:49 +00:00
-> find ( 'authenticators' , [
Query :: equal ( 'userInternalId' , [ $document -> getInternalId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY ),
]));
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'subQueryMemberships' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2022-04-27 12:44:47 +00:00
},
2022-06-01 14:32:59 +00:00
function ( mixed $value , Document $document , Database $database ) {
2024-03-06 17:34:21 +00:00
return Authorization :: skip ( fn () => $database
2022-04-27 12:44:47 +00:00
-> find ( 'memberships' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'userInternalId' , [ $document -> getInternalId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY ),
]));
2021-08-22 15:00:00 +00:00
}
);
2022-07-20 07:18:49 +00:00
Database :: addFilter (
'subQueryVariables' ,
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2022-07-20 07:18:49 +00:00
},
function ( mixed $value , Document $document , Database $database ) {
2022-08-09 12:32:33 +00:00
return $database
2022-07-20 07:18:49 +00:00
-> find ( 'variables' , [
2023-03-11 16:06:02 +00:00
Query :: equal ( 'resourceInternalId' , [ $document -> getInternalId ()]),
Query :: equal ( 'resourceType' , [ 'function' ]),
2022-09-02 14:19:36 +00:00
Query :: limit ( APP_LIMIT_SUBQUERY ),
]);
2022-07-20 07:18:49 +00:00
}
);
2022-05-23 14:54:50 +00:00
Database :: addFilter (
'encrypt' ,
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2024-04-01 11:02:47 +00:00
$key = System :: getEnv ( '_APP_OPENSSL_KEY_V1' );
2021-05-04 21:25:17 +00:00
$iv = OpenSSL :: randomPseudoBytes ( OpenSSL :: cipherIVLength ( OpenSSL :: CIPHER_AES_128_GCM ));
$tag = null ;
2022-05-30 12:01:39 +00:00
2021-05-04 21:25:17 +00:00
return json_encode ([
'data' => OpenSSL :: encrypt ( $value , OpenSSL :: CIPHER_AES_128_GCM , $key , 0 , $iv , $tag ),
'method' => OpenSSL :: CIPHER_AES_128_GCM ,
2021-12-14 12:10:38 +00:00
'iv' => \bin2hex ( $iv ),
'tag' => \bin2hex ( $tag ? ? '' ),
2021-05-04 21:25:17 +00:00
'version' => '1' ,
]);
},
2022-06-01 14:32:59 +00:00
function ( mixed $value ) {
2022-05-23 14:54:50 +00:00
if ( is_null ( $value )) {
2024-03-06 17:34:21 +00:00
return ;
2021-12-03 07:38:21 +00:00
}
2021-05-04 21:25:17 +00:00
$value = json_decode ( $value , true );
2024-04-01 11:02:47 +00:00
$key = System :: getEnv ( '_APP_OPENSSL_KEY_V' . $value [ 'version' ]);
2021-05-04 21:25:17 +00:00
return OpenSSL :: decrypt ( $value [ 'data' ], $value [ 'method' ], $key , 0 , hex2bin ( $value [ 'iv' ]), hex2bin ( $value [ 'tag' ]));
}
);
2023-07-28 07:56:07 +00:00
Database :: addFilter (
'subQueryProjectVariables' ,
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2023-07-28 07:56:07 +00:00
},
function ( mixed $value , Document $document , Database $database ) {
return $database
-> find ( 'variables' , [
Query :: equal ( 'resourceType' , [ 'project' ]),
Query :: limit ( APP_LIMIT_SUBQUERY )
]);
}
);
2023-07-05 19:17:47 +00:00
Database :: addFilter (
'userSearch' ,
function ( mixed $value , Document $user ) {
$searchValues = [
$user -> getId (),
$user -> getAttribute ( 'email' , '' ),
$user -> getAttribute ( 'name' , '' ),
$user -> getAttribute ( 'phone' , '' )
];
foreach ( $user -> getAttribute ( 'labels' , []) as $label ) {
$searchValues [] = 'label:' . $label ;
}
$search = implode ( ' ' , \array_filter ( $searchValues ));
return $search ;
},
function ( mixed $value ) {
return $value ;
}
);
2023-08-16 13:18:38 +00:00
Database :: addFilter (
'subQueryTargets' ,
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2023-08-16 13:18:38 +00:00
},
function ( mixed $value , Document $document , Database $database ) {
2024-03-06 17:34:21 +00:00
return Authorization :: skip ( fn () => $database
2023-08-16 13:18:38 +00:00
-> find ( 'targets' , [
Query :: equal ( 'userInternalId' , [ $document -> getInternalId ()]),
2023-10-25 17:33:23 +00:00
Query :: limit ( APP_LIMIT_SUBQUERY )
2023-08-16 13:18:38 +00:00
]));
}
);
2023-08-17 11:54:45 +00:00
2023-08-24 19:52:16 +00:00
Database :: addFilter (
2023-08-25 10:25:04 +00:00
'subQueryTopicTargets' ,
2023-08-24 19:52:16 +00:00
function ( mixed $value ) {
2024-03-06 17:34:21 +00:00
return ;
2023-08-24 19:52:16 +00:00
},
function ( mixed $value , Document $document , Database $database ) {
$targetIds = Authorization :: skip ( fn () => \array_map (
2024-01-15 05:25:34 +00:00
fn ( $document ) => $document -> getAttribute ( 'targetInternalId' ),
$database -> find ( 'subscribers' , [
2023-08-24 19:52:16 +00:00
Query :: equal ( 'topicInternalId' , [ $document -> getInternalId ()]),
2023-10-26 08:16:45 +00:00
Query :: limit ( APP_LIMIT_SUBSCRIBERS_SUBQUERY )
2023-08-24 23:16:15 +00:00
])
));
2023-08-24 21:02:51 +00:00
if ( \count ( $targetIds ) > 0 ) {
2024-06-20 22:34:08 +00:00
return $database -> skipValidation ( fn () => $database -> find ( 'targets' , [
2024-01-15 05:25:34 +00:00
Query :: equal ( '$internalId' , $targetIds )
2024-06-20 22:34:08 +00:00
]));
2023-08-24 21:02:51 +00:00
}
return [];
2023-08-24 19:52:16 +00:00
}
);
2023-11-14 08:37:52 +00:00
Database :: addFilter (
'providerSearch' ,
function ( mixed $value , Document $provider ) {
$searchValues = [
$provider -> getId (),
$provider -> getAttribute ( 'name' , '' ),
$provider -> getAttribute ( 'provider' , '' ),
$provider -> getAttribute ( 'type' , '' )
];
2023-11-14 09:50:21 +00:00
$search = \implode ( ' ' , \array_filter ( $searchValues ));
2023-11-14 08:37:52 +00:00
return $search ;
},
function ( mixed $value ) {
return $value ;
}
);
Database :: addFilter (
'topicSearch' ,
function ( mixed $value , Document $topic ) {
$searchValues = [
$topic -> getId (),
$topic -> getAttribute ( 'name' , '' ),
$topic -> getAttribute ( 'description' , '' ),
];
2023-11-14 09:50:21 +00:00
$search = \implode ( ' ' , \array_filter ( $searchValues ));
2023-11-14 08:37:52 +00:00
return $search ;
},
function ( mixed $value ) {
return $value ;
}
);
Database :: addFilter (
'messageSearch' ,
function ( mixed $value , Document $message ) {
$searchValues = [
$message -> getId (),
$message -> getAttribute ( 'description' , '' ),
$message -> getAttribute ( 'status' , '' ),
];
2023-11-14 09:50:21 +00:00
$data = \json_decode ( $message -> getAttribute ( 'data' , []), true );
2023-11-29 09:52:26 +00:00
$providerType = $message -> getAttribute ( 'providerType' , '' );
2023-11-14 09:50:21 +00:00
2023-11-29 09:52:26 +00:00
if ( $providerType === MESSAGE_TYPE_EMAIL ) {
2023-11-29 04:05:37 +00:00
$searchValues = \array_merge ( $searchValues , [ $data [ 'subject' ], MESSAGE_TYPE_EMAIL ]);
2023-11-29 09:52:26 +00:00
} elseif ( $providerType === MESSAGE_TYPE_SMS ) {
2023-11-29 04:05:37 +00:00
$searchValues = \array_merge ( $searchValues , [ $data [ 'content' ], MESSAGE_TYPE_SMS ]);
2023-11-14 08:37:52 +00:00
} else {
2023-11-29 04:05:37 +00:00
$searchValues = \array_merge ( $searchValues , [ $data [ 'title' ], MESSAGE_TYPE_PUSH ]);
2023-11-14 08:37:52 +00:00
}
2023-11-14 09:50:21 +00:00
$search = \implode ( ' ' , \array_filter ( $searchValues ));
2023-11-14 08:37:52 +00:00
return $search ;
},
function ( mixed $value ) {
return $value ;
}
);
2021-08-20 11:15:17 +00:00
/**
* DB Formats
*/
2022-05-23 14:54:50 +00:00
Structure :: addFormat ( APP_DATABASE_ATTRIBUTE_EMAIL , function () {
2021-07-26 23:10:39 +00:00
return new Email ();
2021-08-21 15:09:08 +00:00
}, Database :: VAR_STRING );
2021-07-26 23:10:39 +00:00
2022-07-28 12:38:54 +00:00
Structure :: addFormat ( APP_DATABASE_ATTRIBUTE_DATETIME , function () {
return new DatetimeValidator ();
}, Database :: VAR_DATETIME );
2022-05-23 14:54:50 +00:00
Structure :: addFormat ( APP_DATABASE_ATTRIBUTE_ENUM , function ( $attribute ) {
2021-09-10 20:12:22 +00:00
$elements = $attribute [ 'formatOptions' ][ 'elements' ];
2021-12-16 10:15:55 +00:00
return new WhiteList ( $elements , true );
2021-09-10 20:12:22 +00:00
}, Database :: VAR_STRING );
2022-05-23 14:54:50 +00:00
Structure :: addFormat ( APP_DATABASE_ATTRIBUTE_IP , function () {
2021-07-26 23:10:39 +00:00
return new IP ();
2021-08-21 15:09:08 +00:00
}, Database :: VAR_STRING );
2021-07-26 23:10:39 +00:00
2022-05-23 14:54:50 +00:00
Structure :: addFormat ( APP_DATABASE_ATTRIBUTE_URL , function () {
2021-07-26 23:10:39 +00:00
return new URL ();
2021-08-21 15:09:08 +00:00
}, Database :: VAR_STRING );
2021-07-26 23:10:39 +00:00
2022-05-23 14:54:50 +00:00
Structure :: addFormat ( APP_DATABASE_ATTRIBUTE_INT_RANGE , function ( $attribute ) {
2021-08-21 15:09:08 +00:00
$min = $attribute [ 'formatOptions' ][ 'min' ] ? ? - INF ;
$max = $attribute [ 'formatOptions' ][ 'max' ] ? ? INF ;
return new Range ( $min , $max , Range :: TYPE_INTEGER );
}, Database :: VAR_INTEGER );
2021-07-27 18:19:37 +00:00
2022-05-23 14:54:50 +00:00
Structure :: addFormat ( APP_DATABASE_ATTRIBUTE_FLOAT_RANGE , function ( $attribute ) {
2021-08-21 15:09:08 +00:00
$min = $attribute [ 'formatOptions' ][ 'min' ] ? ? - INF ;
$max = $attribute [ 'formatOptions' ][ 'max' ] ? ? INF ;
return new Range ( $min , $max , Range :: TYPE_FLOAT );
}, Database :: VAR_FLOAT );
2021-07-23 14:59:55 +00:00
2019-10-01 04:57:41 +00:00
/*
2019-05-09 06:54:39 +00:00
* Registry
*/
2022-05-23 14:54:50 +00:00
$register -> set ( 'logger' , function () {
2022-06-24 09:48:55 +00:00
// Register error logger
2024-04-01 11:02:47 +00:00
$providerName = System :: getEnv ( '_APP_LOGGING_PROVIDER' , '' );
$providerConfig = System :: getEnv ( '_APP_LOGGING_CONFIG' , '' );
2021-11-22 16:12:18 +00:00
2024-05-23 16:44:19 +00:00
try {
$loggingProvider = new DSN ( $providerConfig ? ? '' );
$providerName = $loggingProvider -> getScheme ();
$providerConfig = match ( $providerName ) {
2024-07-03 15:51:58 +00:00
'sentry' => [ 'key' => $loggingProvider -> getPassword (), 'projectId' => $loggingProvider -> getUser () ? ? '' , 'host' => 'https://' . $loggingProvider -> getHost ()],
2024-05-23 16:44:19 +00:00
'logowl' => [ 'ticket' => $loggingProvider -> getUser () ? ? '' , 'host' => $loggingProvider -> getHost ()],
default => [ 'key' => $loggingProvider -> getHost ()],
};
2024-08-26 10:42:48 +00:00
} catch ( Throwable $th ) {
2024-05-28 14:18:29 +00:00
// Fallback for older Appwrite versions up to 1.5.x that use _APP_LOGGING_PROVIDER and _APP_LOGGING_CONFIG environment variables
2024-08-26 10:42:48 +00:00
Console :: warning ( 'Using deprecated logging configuration. Please update your configuration to use DSN format.' . $th -> getMessage ());
2024-05-23 16:44:19 +00:00
$configChunks = \explode ( " ; " , $providerConfig );
$providerConfig = match ( $providerName ) {
'sentry' => [ 'key' => $configChunks [ 0 ], 'projectId' => $configChunks [ 1 ] ? ? '' , 'host' => '' ,],
'logowl' => [ 'ticket' => $configChunks [ 0 ] ? ? '' , 'host' => '' ],
default => [ 'key' => $providerConfig ],
};
}
2022-05-23 14:54:50 +00:00
if ( empty ( $providerName ) || empty ( $providerConfig )) {
2024-03-06 17:34:21 +00:00
return ;
2021-11-22 16:12:18 +00:00
}
2022-05-23 14:54:50 +00:00
if ( ! Logger :: hasProvider ( $providerName )) {
2022-08-14 05:35:25 +00:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , " Logging provider not supported. Logging is disabled " );
2021-11-22 16:12:18 +00:00
}
2024-08-09 13:05:35 +00:00
try {
$adapter = match ( $providerName ) {
'sentry' => new Sentry ( $providerConfig [ 'projectId' ], $providerConfig [ 'key' ], $providerConfig [ 'host' ]),
'logowl' => new LogOwl ( $providerConfig [ 'ticket' ], $providerConfig [ 'host' ]),
'raygun' => new Raygun ( $providerConfig [ 'key' ]),
'appsignal' => new AppSignal ( $providerConfig [ 'key' ]),
default => null
};
} catch ( Throwable $th ) {
$adapter = null ;
}
2024-05-17 09:01:33 +00:00
2024-09-04 09:06:21 +00:00
if ( $adapter === null ) {
2024-08-09 13:05:35 +00:00
Console :: error ( " Logging provider not supported. Logging is disabled " );
return ;
2024-05-17 09:01:33 +00:00
}
2021-11-22 16:12:18 +00:00
return new Logger ( $adapter );
});
2024-06-20 15:23:06 +00:00
2022-11-15 23:50:37 +00:00
$register -> set ( 'pools' , function () {
2022-10-19 08:35:30 +00:00
$group = new Group ();
2022-06-23 08:50:00 +00:00
2023-08-23 11:52:17 +00:00
$fallbackForDB = 'db_main=' . AppwriteURL :: unparse ([
2022-10-16 11:42:00 +00:00
'scheme' => 'mariadb' ,
2024-04-01 11:02:47 +00:00
'host' => System :: getEnv ( '_APP_DB_HOST' , 'mariadb' ),
'port' => System :: getEnv ( '_APP_DB_PORT' , '3306' ),
'user' => System :: getEnv ( '_APP_DB_USER' , '' ),
'pass' => System :: getEnv ( '_APP_DB_PASS' , '' ),
'path' => System :: getEnv ( '_APP_DB_SCHEMA' , '' ),
2022-10-16 11:42:00 +00:00
]);
2023-08-23 11:52:17 +00:00
$fallbackForRedis = 'redis_main=' . AppwriteURL :: unparse ([
2022-10-16 11:42:00 +00:00
'scheme' => 'redis' ,
2024-04-01 11:02:47 +00:00
'host' => System :: getEnv ( '_APP_REDIS_HOST' , 'redis' ),
'port' => System :: getEnv ( '_APP_REDIS_PORT' , '6379' ),
'user' => System :: getEnv ( '_APP_REDIS_USER' , '' ),
'pass' => System :: getEnv ( '_APP_REDIS_PASS' , '' ),
2022-10-16 11:42:00 +00:00
]);
2019-05-09 06:54:39 +00:00
2022-10-15 08:52:50 +00:00
$connections = [
'console' => [
'type' => 'database' ,
2024-04-01 11:02:47 +00:00
'dsns' => System :: getEnv ( '_APP_CONNECTIONS_DB_CONSOLE' , $fallbackForDB ),
2022-10-15 08:52:50 +00:00
'multiple' => false ,
'schemes' => [ 'mariadb' , 'mysql' ],
],
'database' => [
'type' => 'database' ,
2024-04-01 11:02:47 +00:00
'dsns' => System :: getEnv ( '_APP_CONNECTIONS_DB_PROJECT' , $fallbackForDB ),
2022-10-15 08:52:50 +00:00
'multiple' => true ,
'schemes' => [ 'mariadb' , 'mysql' ],
],
'queue' => [
'type' => 'queue' ,
2024-04-01 11:02:47 +00:00
'dsns' => System :: getEnv ( '_APP_CONNECTIONS_QUEUE' , $fallbackForRedis ),
2022-10-15 08:52:50 +00:00
'multiple' => false ,
'schemes' => [ 'redis' ],
],
'pubsub' => [
'type' => 'pubsub' ,
2024-04-01 11:02:47 +00:00
'dsns' => System :: getEnv ( '_APP_CONNECTIONS_PUBSUB' , $fallbackForRedis ),
2022-10-15 08:52:50 +00:00
'multiple' => false ,
'schemes' => [ 'redis' ],
],
'cache' => [
'type' => 'cache' ,
2024-04-01 11:02:47 +00:00
'dsns' => System :: getEnv ( '_APP_CONNECTIONS_CACHE' , $fallbackForRedis ),
2022-10-16 11:42:00 +00:00
'multiple' => true ,
2022-10-15 08:52:50 +00:00
'schemes' => [ 'redis' ],
],
];
2024-04-01 11:02:47 +00:00
$maxConnections = System :: getEnv ( '_APP_CONNECTIONS_MAX' , 151 );
$instanceConnections = $maxConnections / System :: getEnv ( '_APP_POOL_CLIENTS' , 14 );
2022-11-22 07:17:56 +00:00
2024-04-01 11:02:47 +00:00
$multiprocessing = System :: getEnv ( '_APP_SERVER_MULTIPROCESS' , 'disabled' ) === 'enabled' ;
2022-11-22 07:17:56 +00:00
2022-11-22 07:57:44 +00:00
if ( $multiprocessing ) {
2024-04-01 11:02:47 +00:00
$workerCount = swoole_cpu_num () * intval ( System :: getEnv ( '_APP_WORKER_PER_CORE' , 6 ));
2022-11-22 07:17:56 +00:00
} else {
$workerCount = 1 ;
}
2022-11-15 23:50:37 +00:00
2022-11-16 07:18:59 +00:00
if ( $workerCount > $instanceConnections ) {
throw new \Exception ( 'Pool size is too small. Increase the number of allowed database connections or decrease the number of workers.' , 500 );
2021-06-11 16:09:46 +00:00
}
2019-05-09 06:54:39 +00:00
2022-11-16 07:18:59 +00:00
$poolSize = ( int )( $instanceConnections / $workerCount );
2022-11-15 23:50:37 +00:00
2022-10-15 08:52:50 +00:00
foreach ( $connections as $key => $connection ) {
$type = $connection [ 'type' ] ? ? '' ;
2023-11-22 08:32:36 +00:00
$multiple = $connection [ 'multiple' ] ? ? false ;
2022-10-15 08:52:50 +00:00
$schemes = $connection [ 'schemes' ] ? ? [];
2022-10-15 14:14:17 +00:00
$config = [];
$dsns = explode ( ',' , $connection [ 'dsns' ] ? ? '' );
foreach ( $dsns as & $dsn ) {
2022-10-15 08:52:50 +00:00
$dsn = explode ( '=' , $dsn );
2023-11-22 08:32:36 +00:00
$name = ( $multiple ) ? $key . '_' . $dsn [ 0 ] : $key ;
2022-10-15 14:14:17 +00:00
$dsn = $dsn [ 1 ] ? ? '' ;
$config [] = $name ;
2022-10-19 08:35:30 +00:00
if ( empty ( $dsn )) {
2022-10-15 18:17:03 +00:00
//throw new Exception(Exception::GENERAL_SERVER_ERROR, "Missing value for DSN connection in {$key}");
continue ;
2022-10-15 14:14:17 +00:00
}
2022-10-15 08:52:50 +00:00
$dsn = new DSN ( $dsn );
$dsnHost = $dsn -> getHost ();
$dsnPort = $dsn -> getPort ();
$dsnUser = $dsn -> getUser ();
$dsnPass = $dsn -> getPassword ();
2022-10-19 13:55:58 +00:00
$dsnScheme = $dsn -> getScheme ();
2022-11-17 14:56:10 +00:00
$dsnDatabase = $dsn -> getPath ();
2022-10-15 08:52:50 +00:00
2022-11-15 16:03:42 +00:00
if ( ! in_array ( $dsnScheme , $schemes )) {
2022-10-15 08:52:50 +00:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , " Invalid console database scheme " );
}
/**
* Get Resource
2022-10-19 08:35:30 +00:00
*
2023-12-08 17:33:35 +00:00
* Creation could be reused across connection types like database , cache , queue , etc .
2022-10-19 08:35:30 +00:00
*
2022-10-15 08:52:50 +00:00
* Resource assignment to an adapter will happen below .
*/
2023-12-08 17:33:35 +00:00
$resource = match ( $dsnScheme ) {
'mysql' ,
'mariadb' => function () use ( $dsnHost , $dsnPort , $dsnUser , $dsnPass , $dsnDatabase ) {
return new PDOProxy ( function () use ( $dsnHost , $dsnPort , $dsnUser , $dsnPass , $dsnDatabase ) {
return new PDO ( " mysql:host= { $dsnHost } ;port= { $dsnPort } ;dbname= { $dsnDatabase } ;charset=utf8mb4 " , $dsnUser , $dsnPass , array (
PDO :: ATTR_TIMEOUT => 3 , // Seconds
PDO :: ATTR_PERSISTENT => true ,
PDO :: ATTR_DEFAULT_FETCH_MODE => PDO :: FETCH_ASSOC ,
PDO :: ATTR_EMULATE_PREPARES => true ,
PDO :: ATTR_STRINGIFY_FETCHES => true
));
});
},
'redis' => function () use ( $dsnHost , $dsnPort , $dsnPass ) {
$redis = new Redis ();
@ $redis -> pconnect ( $dsnHost , ( int ) $dsnPort );
if ( $dsnPass ) {
$redis -> auth ( $dsnPass );
}
$redis -> setOption ( Redis :: OPT_READ_TIMEOUT , - 1 );
return $redis ;
},
2024-04-30 07:40:47 +00:00
default => throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Invalid scheme' ),
2023-12-08 17:33:35 +00:00
};
2024-10-14 13:18:01 +00:00
2022-11-16 07:18:59 +00:00
$pool = new Pool ( $name , $poolSize , function () use ( $type , $resource , $dsn ) {
2022-10-16 22:49:53 +00:00
// Get Adapter
switch ( $type ) {
case 'database' :
$adapter = match ( $dsn -> getScheme ()) {
'mariadb' => new MariaDB ( $resource ()),
'mysql' => new MySQL ( $resource ()),
default => null
};
2022-10-19 08:35:30 +00:00
2023-11-22 08:32:36 +00:00
$adapter -> setDatabase ( $dsn -> getPath ());
2022-10-16 22:49:53 +00:00
break ;
case 'pubsub' :
2024-10-31 12:12:03 +00:00
$adapter = match ( $dsn -> getScheme ()) {
'redis' => new PubSub ( $resource ()),
default => null
};
2022-11-15 16:03:42 +00:00
break ;
2022-11-09 17:01:43 +00:00
case 'queue' :
$adapter = match ( $dsn -> getScheme ()) {
'redis' => new Queue\Connection\Redis ( $dsn -> getHost (), $dsn -> getPort ()),
2022-11-15 16:03:42 +00:00
default => null
2022-11-09 17:01:43 +00:00
};
2022-10-16 22:49:53 +00:00
break ;
case 'cache' :
$adapter = match ( $dsn -> getScheme ()) {
'redis' => new RedisCache ( $resource ()),
default => null
};
break ;
2022-10-19 08:35:30 +00:00
2022-10-16 22:49:53 +00:00
default :
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , " Server error: Missing adapter implementation. " );
}
2022-10-19 08:35:30 +00:00
2022-10-15 14:14:17 +00:00
return $adapter ;
2022-10-15 08:52:50 +00:00
});
$group -> add ( $pool );
}
2022-10-15 14:14:17 +00:00
2022-10-19 08:35:30 +00:00
Config :: setParam ( 'pools-' . $key , $config );
2021-06-11 16:09:46 +00:00
}
2019-05-09 06:54:39 +00:00
2022-10-15 08:52:50 +00:00
return $group ;
2019-05-09 06:54:39 +00:00
});
2022-11-15 16:03:42 +00:00
2023-11-20 16:31:20 +00:00
$register -> set ( 'db' , function () {
// This is usually for our workers or CLI commands scope
2024-04-01 11:02:47 +00:00
$dbHost = System :: getEnv ( '_APP_DB_HOST' , '' );
$dbPort = System :: getEnv ( '_APP_DB_PORT' , '' );
$dbUser = System :: getEnv ( '_APP_DB_USER' , '' );
$dbPass = System :: getEnv ( '_APP_DB_PASS' , '' );
$dbScheme = System :: getEnv ( '_APP_DB_SCHEMA' , '' );
2023-12-24 09:55:51 +00:00
return new PDO (
" mysql:host= { $dbHost } ;port= { $dbPort } ;dbname= { $dbScheme } ;charset=utf8mb4 " ,
$dbUser ,
$dbPass ,
SQL :: getPDOAttributes ()
);
2023-11-20 16:31:20 +00:00
});
2023-08-20 12:29:43 +00:00
2020-06-28 20:45:36 +00:00
$register -> set ( 'smtp' , function () {
2019-08-08 21:49:46 +00:00
$mail = new PHPMailer ( true );
2019-05-09 06:54:39 +00:00
2019-08-08 21:49:46 +00:00
$mail -> isSMTP ();
2019-05-09 06:54:39 +00:00
2024-04-01 11:02:47 +00:00
$username = System :: getEnv ( '_APP_SMTP_USERNAME' );
$password = System :: getEnv ( '_APP_SMTP_PASSWORD' );
2019-08-08 21:49:46 +00:00
2019-10-01 04:57:41 +00:00
$mail -> XMailer = 'Appwrite Mailer' ;
2024-04-01 11:02:47 +00:00
$mail -> Host = System :: getEnv ( '_APP_SMTP_HOST' , 'smtp' );
$mail -> Port = System :: getEnv ( '_APP_SMTP_PORT' , 25 );
2023-08-30 04:56:08 +00:00
$mail -> SMTPAuth = ! empty ( $username ) && ! empty ( $password );
2019-10-01 04:57:41 +00:00
$mail -> Username = $username ;
$mail -> Password = $password ;
2024-04-01 11:02:47 +00:00
$mail -> SMTPSecure = System :: getEnv ( '_APP_SMTP_SECURE' , '' );
2020-01-11 13:58:02 +00:00
$mail -> SMTPAutoTLS = false ;
2020-06-12 16:49:56 +00:00
$mail -> CharSet = 'UTF-8' ;
2019-08-08 21:49:46 +00:00
2024-04-01 11:02:47 +00:00
$from = \urldecode ( System :: getEnv ( '_APP_SYSTEM_EMAIL_NAME' , APP_NAME . ' Server' ));
$email = System :: getEnv ( '_APP_SYSTEM_EMAIL_ADDRESS' , APP_EMAIL_TEAM );
2020-02-07 23:19:13 +00:00
$mail -> setFrom ( $email , $from );
$mail -> addReplyTo ( $email , $from );
2019-05-09 06:54:39 +00:00
2019-08-08 21:49:46 +00:00
$mail -> isHTML ( true );
2019-09-28 01:48:50 +00:00
2019-08-08 21:49:46 +00:00
return $mail ;
2019-05-09 06:54:39 +00:00
});
2020-10-29 14:08:09 +00:00
$register -> set ( 'geodb' , function () {
2024-09-03 07:42:40 +00:00
return new Reader ( __DIR__ . '/assets/dbip/dbip-country-lite-2024-09.mmdb' );
2023-05-23 13:43:03 +00:00
});
2022-12-26 09:24:51 +00:00
$register -> set ( 'passwordsDictionary' , function () {
2022-12-26 10:22:38 +00:00
$content = \file_get_contents ( __DIR__ . '/assets/security/10k-common-passwords' );
2022-12-27 06:16:19 +00:00
$content = explode ( " \n " , $content );
2022-12-26 10:22:38 +00:00
$content = array_flip ( $content );
return $content ;
2022-12-23 07:19:11 +00:00
});
2023-05-23 13:43:03 +00:00
$register -> set ( 'promiseAdapter' , function () {
return new Swoole ();
2020-10-29 14:08:09 +00:00
});
2023-12-15 22:19:43 +00:00
$register -> set ( 'hooks' , function () {
return new Hooks ();
});
2019-10-01 04:57:41 +00:00
/*
2019-05-09 06:54:39 +00:00
* Localization
*/
Locale :: $exceptions = false ;
2023-04-17 02:10:17 +00:00
$locales = Config :: getParam ( 'locale-codes' , []);
2023-04-17 02:15:46 +00:00
foreach ( $locales as $locale ) {
2023-04-17 02:10:17 +00:00
$code = $locale [ 'code' ];
2023-04-18 07:14:03 +00:00
2023-04-17 02:10:17 +00:00
$path = __DIR__ . '/config/locale/translations/' . $code . '.json' ;
2023-04-17 02:15:46 +00:00
if ( ! \file_exists ( $path )) {
2023-04-17 09:10:41 +00:00
$path = __DIR__ . '/config/locale/translations/' . \substr ( $code , 0 , 2 ) . '.json' ; // if `ar-ae` doesn't exist, look for `ar`
2023-04-18 07:14:03 +00:00
if ( ! \file_exists ( $path )) {
2023-04-17 09:10:41 +00:00
$path = __DIR__ . '/config/locale/translations/en.json' ; // if none translation exists, use default from `en.json`
}
2023-04-17 02:10:17 +00:00
}
2023-04-17 09:10:41 +00:00
Locale :: setLanguageFromJSON ( $code , $path );
2023-04-17 02:10:17 +00:00
}
2019-10-09 04:33:33 +00:00
2020-06-20 11:20:49 +00:00
\stream_context_set_default ([ // Set global user agent and http settings
2019-05-09 06:54:39 +00:00
'http' => [
'method' => 'GET' ,
2022-05-23 14:54:50 +00:00
'user_agent' => \sprintf (
APP_USERAGENT ,
2024-04-01 11:02:47 +00:00
System :: getEnv ( '_APP_VERSION' , 'UNKNOWN' ),
2024-05-06 01:04:44 +00:00
System :: getEnv ( '_APP_EMAIL_SECURITY' , System :: getEnv ( '_APP_SYSTEM_SECURITY_EMAIL_ADDRESS' , APP_EMAIL_SECURITY ))
2022-05-23 14:54:50 +00:00
),
2019-10-01 04:57:41 +00:00
'timeout' => 2 ,
],
2019-05-09 06:54:39 +00:00
]);
2020-06-30 04:34:13 +00:00
// Runtime Execution
2024-03-06 17:34:21 +00:00
App :: setResource ( 'log' , fn () => new Log ());
2022-05-23 14:54:50 +00:00
App :: setResource ( 'logger' , function ( $register ) {
2021-11-22 16:12:18 +00:00
return $register -> get ( 'logger' );
}, [ 'register' ]);
2020-06-30 04:34:13 +00:00
2023-12-15 22:19:43 +00:00
App :: setResource ( 'hooks' , function ( $register ) {
return $register -> get ( 'hooks' );
}, [ 'register' ]);
2024-03-06 17:34:21 +00:00
App :: setResource ( 'register' , fn () => $register );
2024-04-01 11:02:47 +00:00
App :: setResource ( 'locale' , fn () => new Locale ( System :: getEnv ( '_APP_LOCALE' , 'en' )));
2020-06-30 04:34:13 +00:00
2023-04-17 02:15:46 +00:00
App :: setResource ( 'localeCodes' , function () {
2024-03-06 17:34:21 +00:00
return array_map ( fn ( $locale ) => $locale [ 'code' ], Config :: getParam ( 'locale-codes' , []));
2023-04-17 02:10:17 +00:00
});
2020-06-30 04:34:13 +00:00
// Queues
2022-11-18 14:20:05 +00:00
App :: setResource ( 'queue' , function ( Group $pools ) {
2022-11-16 19:39:35 +00:00
return $pools -> get ( 'queue' ) -> pop () -> getResource ();
2022-11-15 18:13:17 +00:00
}, [ 'pools' ]);
2022-12-20 16:11:30 +00:00
App :: setResource ( 'queueForMessaging' , function ( Connection $queue ) {
2023-10-20 09:25:17 +00:00
return new Messaging ( $queue );
2022-12-17 20:45:58 +00:00
}, [ 'queue' ]);
2023-06-11 14:08:48 +00:00
App :: setResource ( 'queueForMails' , function ( Connection $queue ) {
2022-12-20 11:24:26 +00:00
return new Mail ( $queue );
}, [ 'queue' ]);
2022-12-20 16:11:30 +00:00
App :: setResource ( 'queueForBuilds' , function ( Connection $queue ) {
2022-12-20 12:22:58 +00:00
return new Build ( $queue );
}, [ 'queue' ]);
2022-12-20 16:11:30 +00:00
App :: setResource ( 'queueForDatabase' , function ( Connection $queue ) {
2022-12-20 11:23:26 +00:00
return new EventDatabase ( $queue );
2022-12-20 12:22:58 +00:00
}, [ 'queue' ]);
2022-12-20 16:11:30 +00:00
App :: setResource ( 'queueForDeletes' , function ( Connection $queue ) {
2022-12-20 11:23:26 +00:00
return new Delete ( $queue );
}, [ 'queue' ]);
2022-12-20 16:11:30 +00:00
App :: setResource ( 'queueForEvents' , function ( Connection $queue ) {
2023-06-02 03:54:34 +00:00
return new Event ( $queue );
2022-12-20 12:22:58 +00:00
}, [ 'queue' ]);
2024-11-04 15:05:54 +00:00
App :: setResource ( 'queueForWebhooks' , function ( Connection $queue ) {
return new Webhook ( $queue );
}, [ 'queue' ]);
App :: setResource ( 'queueForRealtime' , function () {
return new Realtime ();
}, []);
2022-12-20 16:11:30 +00:00
App :: setResource ( 'queueForAudits' , function ( Connection $queue ) {
2022-12-20 11:11:36 +00:00
return new Audit ( $queue );
2022-12-20 12:22:58 +00:00
}, [ 'queue' ]);
2022-11-18 14:20:05 +00:00
App :: setResource ( 'queueForFunctions' , function ( Connection $queue ) {
return new Func ( $queue );
}, [ 'queue' ]);
2023-10-25 07:39:59 +00:00
App :: setResource ( 'queueForUsage' , function ( Connection $queue ) {
return new Usage ( $queue );
}, [ 'queue' ]);
2022-12-20 16:11:30 +00:00
App :: setResource ( 'queueForCertificates' , function ( Connection $queue ) {
2022-12-13 11:16:12 +00:00
return new Certificate ( $queue );
}, [ 'queue' ]);
2023-10-01 17:39:26 +00:00
App :: setResource ( 'queueForMigrations' , function ( Connection $queue ) {
return new Migration ( $queue );
}, [ 'queue' ]);
2021-12-27 12:45:23 +00:00
App :: setResource ( 'clients' , function ( $request , $console , $project ) {
2021-08-20 11:15:17 +00:00
$console -> setAttribute ( 'platforms' , [ // Always allow current host
2022-08-14 10:33:36 +00:00
'$collection' => ID :: custom ( 'platforms' ),
2021-01-12 16:36:21 +00:00
'name' => 'Current Host' ,
2023-05-23 13:43:03 +00:00
'type' => Origin :: CLIENT_TYPE_WEB ,
2021-01-12 16:36:21 +00:00
'hostname' => $request -> getHostname (),
], Document :: SET_TYPE_APPEND );
2021-12-21 10:48:10 +00:00
2024-04-01 11:02:47 +00:00
$hostnames = explode ( ',' , System :: getEnv ( '_APP_CONSOLE_HOSTNAMES' , '' ));
2024-01-03 19:25:54 +00:00
$validator = new Hostname ();
foreach ( $hostnames as $hostname ) {
$hostname = trim ( $hostname );
if ( ! $validator -> isValid ( $hostname )) {
continue ;
2023-12-29 20:52:50 +00:00
}
2024-01-03 19:25:54 +00:00
$console -> setAttribute ( 'platforms' , [
'$collection' => ID :: custom ( 'platforms' ),
'type' => Origin :: CLIENT_TYPE_WEB ,
'name' => $hostname ,
'hostname' => $hostname ,
], Document :: SET_TYPE_APPEND );
2023-12-29 20:52:50 +00:00
}
2020-06-30 18:08:02 +00:00
/**
* Get All verified client URLs for both console and current projects
* + Filter for duplicated entries
*/
2021-12-27 12:45:23 +00:00
$clientsConsole = \array_map (
fn ( $node ) => $node [ 'hostname' ],
\array_filter (
$console -> getAttribute ( 'platforms' , []),
2023-11-27 02:22:05 +00:00
fn ( $node ) => ( isset ( $node [ 'type' ]) && ( $node [ 'type' ] === Origin :: CLIENT_TYPE_WEB ) && ! empty ( $node [ 'hostname' ]))
2021-12-27 12:45:23 +00:00
)
);
2023-11-27 02:22:05 +00:00
$clients = $clientsConsole ;
$platforms = $project -> getAttribute ( 'platforms' , []);
foreach ( $platforms as $node ) {
if (
isset ( $node [ 'type' ]) &&
( $node [ 'type' ] === Origin :: CLIENT_TYPE_WEB ||
$node [ 'type' ] === Origin :: CLIENT_TYPE_FLUTTER_WEB ) &&
! empty ( $node [ 'hostname' ])
) {
$clients [] = $node [ 'hostname' ];
}
}
2020-06-30 18:08:02 +00:00
2023-11-27 11:26:35 +00:00
return \array_unique ( $clients );
2021-01-12 16:36:21 +00:00
}, [ 'request' , 'console' , 'project' ]);
2020-06-30 18:08:02 +00:00
2022-05-23 14:54:50 +00:00
App :: setResource ( 'user' , function ( $mode , $project , $console , $request , $response , $dbForProject , $dbForConsole ) {
2021-12-31 15:50:07 +00:00
/** @var Appwrite\Utopia\Request $request */
2020-10-29 13:50:49 +00:00
/** @var Appwrite\Utopia\Response $response */
2021-05-06 22:31:05 +00:00
/** @var Utopia\Database\Document $project */
2021-12-27 12:45:23 +00:00
/** @var Utopia\Database\Database $dbForProject */
2021-05-06 22:31:05 +00:00
/** @var Utopia\Database\Database $dbForConsole */
2021-06-11 16:09:46 +00:00
/** @var string $mode */
2020-06-30 18:08:02 +00:00
2020-07-03 06:08:37 +00:00
Authorization :: setDefaultStatus ( true );
2022-05-23 14:54:50 +00:00
Auth :: setCookieName ( 'a_session_' . $project -> getId ());
2020-06-30 18:08:02 +00:00
if ( APP_MODE_ADMIN === $mode ) {
2022-05-23 14:54:50 +00:00
Auth :: setCookieName ( 'a_session_' . $console -> getId ());
2020-06-30 18:08:02 +00:00
}
$session = Auth :: decodeSession (
2022-05-23 14:54:50 +00:00
$request -> getCookie (
Auth :: $cookieName , // Get sessions
$request -> getCookie ( Auth :: $cookieName . '_legacy' , '' )
)
2023-12-12 15:39:24 +00:00
);
// Get session from header for SSR clients
if ( empty ( $session [ 'id' ]) && empty ( $session [ 'secret' ])) {
$sessionHeader = $request -> getHeader ( 'x-appwrite-session' , '' );
2020-06-30 18:08:02 +00:00
2023-12-12 15:39:24 +00:00
if ( ! empty ( $sessionHeader )) {
$session = Auth :: decodeSession ( $sessionHeader );
}
}
2020-06-30 18:08:02 +00:00
2023-12-12 15:39:24 +00:00
// Get fallback session from old clients (no SameSite support) or clients who block 3rd-party cookies
2022-05-23 14:54:50 +00:00
if ( $response ) {
$response -> addHeader ( 'X-Debug-Fallback' , 'false' );
}
2020-06-30 18:08:02 +00:00
2022-05-23 14:54:50 +00:00
if ( empty ( $session [ 'id' ]) && empty ( $session [ 'secret' ])) {
if ( $response ) {
$response -> addHeader ( 'X-Debug-Fallback' , 'true' );
}
2020-07-04 22:22:22 +00:00
$fallback = $request -> getHeader ( 'x-fallback-cookies' , '' );
2020-06-30 18:08:02 +00:00
$fallback = \json_decode ( $fallback , true );
$session = Auth :: decodeSession ((( isset ( $fallback [ Auth :: $cookieName ])) ? $fallback [ Auth :: $cookieName ] : '' ));
}
2020-07-03 05:56:28 +00:00
2021-05-06 22:31:05 +00:00
Auth :: $unique = $session [ 'id' ] ? ? '' ;
Auth :: $secret = $session [ 'secret' ] ? ? '' ;
2020-06-30 18:08:02 +00:00
2021-05-16 10:55:12 +00:00
if ( APP_MODE_ADMIN !== $mode ) {
2021-05-17 09:37:33 +00:00
if ( $project -> isEmpty ()) {
2023-08-11 10:49:05 +00:00
$user = new Document ([]);
2022-05-23 14:54:50 +00:00
} else {
2023-06-18 14:08:53 +00:00
if ( $project -> getId () === 'console' ) {
2023-06-18 11:38:37 +00:00
$user = $dbForConsole -> getDocument ( 'users' , Auth :: $unique );
} else {
$user = $dbForProject -> getDocument ( 'users' , Auth :: $unique );
}
2021-05-17 09:37:33 +00:00
}
2022-05-23 14:54:50 +00:00
} else {
2021-05-06 22:31:05 +00:00
$user = $dbForConsole -> getDocument ( 'users' , Auth :: $unique );
2020-06-30 18:08:02 +00:00
}
2020-06-30 04:34:13 +00:00
2022-05-23 14:54:50 +00:00
if (
$user -> isEmpty () // Check a document has been found in the DB
2024-01-15 14:37:47 +00:00
|| ! Auth :: sessionVerify ( $user -> getAttribute ( 'sessions' , []), Auth :: $secret )
2022-05-23 14:54:50 +00:00
) { // Validate user has valid login token
2023-08-11 10:49:05 +00:00
$user = new Document ([]);
2020-06-30 18:08:02 +00:00
}
2024-07-23 19:49:11 +00:00
// if (APP_MODE_ADMIN === $mode) {
// if ($user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships')) {
// Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
// } else {
// $user = new Document([]);
// }
// }
2020-06-30 18:08:02 +00:00
2020-12-28 20:31:42 +00:00
$authJWT = $request -> getHeader ( 'x-appwrite-jwt' , '' );
2021-05-17 09:37:33 +00:00
if ( ! empty ( $authJWT ) && ! $project -> isEmpty ()) { // JWT authentication
2024-05-29 08:57:25 +00:00
$jwt = new JWT ( System :: getEnv ( '_APP_OPENSSL_KEY_V1' ), 'HS256' , 3600 , 0 );
2020-12-28 21:23:09 +00:00
2020-12-28 20:31:42 +00:00
try {
$payload = $jwt -> decode ( $authJWT );
} catch ( JWTException $error ) {
2022-08-14 05:35:25 +00:00
throw new Exception ( Exception :: USER_JWT_INVALID , 'Failed to verify JWT. ' . $error -> getMessage ());
2020-12-28 20:31:42 +00:00
}
2021-08-17 08:58:33 +00:00
2020-12-28 20:31:42 +00:00
$jwtUserId = $payload [ 'userId' ] ? ? '' ;
2024-07-21 13:28:23 +00:00
if ( ! empty ( $jwtUserId )) {
2021-12-27 12:45:23 +00:00
$user = $dbForProject -> getDocument ( 'users' , $jwtUserId );
2020-12-28 20:31:42 +00:00
}
2024-07-21 13:28:23 +00:00
$jwtSessionId = $payload [ 'sessionId' ] ? ? '' ;
2024-09-04 09:06:21 +00:00
if ( ! empty ( $jwtSessionId )) {
2024-07-21 13:28:23 +00:00
if ( empty ( $user -> find ( '$id' , $jwtSessionId , 'sessions' ))) { // Match JWT to active token
$user = new Document ([]);
}
2020-12-28 20:31:42 +00:00
}
}
2023-10-18 03:21:10 +00:00
$dbForProject -> setMetadata ( 'user' , $user -> getId ());
$dbForConsole -> setMetadata ( 'user' , $user -> getId ());
2020-06-30 18:08:02 +00:00
return $user ;
2021-12-27 12:45:23 +00:00
}, [ 'mode' , 'project' , 'console' , 'request' , 'response' , 'dbForProject' , 'dbForConsole' ]);
2020-06-30 18:08:02 +00:00
2022-05-23 14:54:50 +00:00
App :: setResource ( 'project' , function ( $dbForConsole , $request , $console ) {
2021-12-31 15:50:07 +00:00
/** @var Appwrite\Utopia\Request $request */
2021-05-17 09:37:33 +00:00
/** @var Utopia\Database\Database $dbForConsole */
/** @var Utopia\Database\Document $console */
2021-05-16 09:18:34 +00:00
2023-06-02 23:22:54 +00:00
$projectId = $request -> getParam ( 'project' , $request -> getHeader ( 'x-appwrite-project' , '' ));
2020-06-30 04:34:13 +00:00
2023-08-06 10:30:38 +00:00
if ( empty ( $projectId ) || $projectId === 'console' ) {
2021-05-16 09:18:34 +00:00
return $console ;
}
2020-07-01 08:55:14 +00:00
2024-03-06 17:34:21 +00:00
$project = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'projects' , $projectId ));
2020-06-30 18:08:02 +00:00
2024-11-26 05:29:10 +00:00
if ( $project -> getAttribute ( 'region' ) !== System :: getEnv ( '_APP_REGION' )) {
2024-11-26 09:50:34 +00:00
var_dump ( System :: getEnv ( '_APP_REGION' ));
var_dump ( $project -> getAttribute ( 'region' ));
2024-11-10 10:26:34 +00:00
throw new Exception ( Exception :: GENERAL_ACCESS_FORBIDDEN , 'Project is not accessible in this region. Please make sure you are using the correct endpoint' );
}
2020-06-30 18:08:02 +00:00
return $project ;
2021-05-16 09:18:34 +00:00
}, [ 'dbForConsole' , 'request' , 'console' ]);
2024-05-07 00:16:56 +00:00
App :: setResource ( 'session' , function ( Document $user ) {
2023-06-22 13:35:49 +00:00
if ( $user -> isEmpty ()) {
2024-03-06 17:34:21 +00:00
return ;
2023-06-22 13:35:49 +00:00
}
$sessions = $user -> getAttribute ( 'sessions' , []);
2024-05-07 00:16:56 +00:00
$sessionId = Auth :: sessionVerify ( $user -> getAttribute ( 'sessions' ), Auth :: $secret );
2023-06-22 13:35:49 +00:00
if ( ! $sessionId ) {
2024-03-06 17:34:21 +00:00
return ;
2023-06-22 13:35:49 +00:00
}
foreach ( $sessions as $session ) { /** @var Document $session */
if ( $sessionId === $session -> getId ()) {
return $session ;
}
}
2024-03-06 17:34:21 +00:00
return ;
2024-05-07 00:16:56 +00:00
}, [ 'user' ]);
2023-06-22 13:35:49 +00:00
2022-05-23 14:54:50 +00:00
App :: setResource ( 'console' , function () {
2021-08-20 11:15:17 +00:00
return new Document ([
2022-08-14 10:33:36 +00:00
'$id' => ID :: custom ( 'console' ),
'$internalId' => ID :: custom ( 'console' ),
2021-05-16 09:18:34 +00:00
'name' => 'Appwrite' ,
2022-08-14 10:33:36 +00:00
'$collection' => ID :: custom ( 'projects' ),
2021-05-16 09:18:34 +00:00
'description' => 'Appwrite core engine' ,
'logo' => '' ,
2024-07-23 19:49:11 +00:00
'teamId' => null ,
2021-05-16 09:18:34 +00:00
'webhooks' => [],
'keys' => [],
'platforms' => [
[
2022-08-14 10:33:36 +00:00
'$collection' => ID :: custom ( 'platforms' ),
2021-05-16 09:18:34 +00:00
'name' => 'Localhost' ,
2023-05-23 13:43:03 +00:00
'type' => Origin :: CLIENT_TYPE_WEB ,
2021-05-16 09:18:34 +00:00
'hostname' => 'localhost' ,
], // Current host is added on app init
],
'legalName' => '' ,
'legalCountry' => '' ,
'legalState' => '' ,
'legalCity' => '' ,
'legalAddress' => '' ,
'legalTaxId' => '' ,
2021-08-06 08:34:17 +00:00
'auths' => [
2024-07-03 08:27:54 +00:00
'mockNumbers' => [],
2024-04-01 11:02:47 +00:00
'invites' => System :: getEnv ( '_APP_CONSOLE_INVITES' , 'enabled' ) === 'enabled' ,
'limit' => ( System :: getEnv ( '_APP_CONSOLE_WHITELIST_ROOT' , 'enabled' ) === 'enabled' ) ? 1 : 0 , // limit signup to 1 user
2022-11-14 09:30:45 +00:00
'duration' => Auth :: TOKEN_EXPIRATION_LOGIN_LONG , // 1 Year in seconds
2024-07-03 07:11:15 +00:00
'sessionAlerts' => System :: getEnv ( '_APP_CONSOLE_SESSION_ALERTS' , 'disabled' ) === 'enabled'
2021-08-06 08:34:17 +00:00
],
2024-04-01 11:02:47 +00:00
'authWhitelistEmails' => ( ! empty ( System :: getEnv ( '_APP_CONSOLE_WHITELIST_EMAILS' , null ))) ? \explode ( ',' , System :: getEnv ( '_APP_CONSOLE_WHITELIST_EMAILS' , null )) : [],
'authWhitelistIPs' => ( ! empty ( System :: getEnv ( '_APP_CONSOLE_WHITELIST_IPS' , null ))) ? \explode ( ',' , System :: getEnv ( '_APP_CONSOLE_WHITELIST_IPS' , null )) : [],
2023-10-25 17:33:23 +00:00
'oAuthProviders' => [
2023-04-17 12:22:47 +00:00
'githubEnabled' => true ,
2024-04-01 11:02:47 +00:00
'githubSecret' => System :: getEnv ( '_APP_CONSOLE_GITHUB_SECRET' , '' ),
'githubAppid' => System :: getEnv ( '_APP_CONSOLE_GITHUB_APP_ID' , '' )
2023-04-17 12:22:47 +00:00
],
2024-11-10 10:26:34 +00:00
'region' => System :: getEnv ( '_APP_REGION' , 'default' )
2021-05-16 09:18:34 +00:00
]);
}, []);
2020-06-30 04:34:13 +00:00
2022-10-15 14:14:17 +00:00
App :: setResource ( 'dbForProject' , function ( Group $pools , Database $dbForConsole , Cache $cache , Document $project ) {
2022-10-19 08:35:30 +00:00
if ( $project -> isEmpty () || $project -> getId () === 'console' ) {
2022-10-15 14:14:17 +00:00
return $dbForConsole ;
}
2021-05-03 08:28:31 +00:00
2024-05-06 09:19:19 +00:00
try {
$dsn = new DSN ( $project -> getAttribute ( 'database' ));
} catch ( \InvalidArgumentException ) {
2024-05-07 02:07:04 +00:00
// TODO: Temporary until all projects are using shared tables
2024-05-06 09:19:19 +00:00
$dsn = new DSN ( 'mysql://' . $project -> getAttribute ( 'database' ));
}
2022-10-15 08:52:50 +00:00
$dbAdapter = $pools
2024-05-06 09:19:19 +00:00
-> get ( $dsn -> getHost ())
2022-10-15 08:52:50 +00:00
-> pop ()
2023-10-19 02:32:45 +00:00
-> getResource ();
2022-10-15 08:52:50 +00:00
$database = new Database ( $dbAdapter , $cache );
2023-10-19 02:32:45 +00:00
$database
2023-10-18 03:21:10 +00:00
-> setMetadata ( 'host' , \gethostname ())
2023-10-26 09:28:23 +00:00
-> setMetadata ( 'project' , $project -> getId ())
2024-10-15 12:50:02 +00:00
-> setTimeout ( APP_DATABASE_TIMEOUT_MILLISECONDS )
2024-10-16 08:35:32 +00:00
-> setMaxQueryValues ( APP_DATABASE_QUERY_MAX_VALUES );
2021-05-03 08:28:31 +00:00
2024-10-20 07:56:44 +00:00
$sharedTables = \explode ( ',' , System :: getEnv ( '_APP_DATABASE_SHARED_TABLES' , '' ));
if ( \in_array ( $dsn -> getHost (), $sharedTables )) {
$database
2024-03-07 16:49:59 +00:00
-> setSharedTables ( true )
2023-11-27 11:26:35 +00:00
-> setTenant ( $project -> getInternalId ())
2024-05-06 05:33:36 +00:00
-> setNamespace ( $dsn -> getParam ( 'namespace' ));
2024-03-07 13:52:13 +00:00
} else {
$database
2024-03-07 16:49:59 +00:00
-> setSharedTables ( false )
2024-03-07 13:52:13 +00:00
-> setTenant ( null )
-> setNamespace ( '_' . $project -> getInternalId ());
}
2021-05-03 08:28:31 +00:00
return $database ;
2022-10-15 14:14:17 +00:00
}, [ 'pools' , 'dbForConsole' , 'cache' , 'project' ]);
2022-10-15 08:52:50 +00:00
App :: setResource ( 'dbForConsole' , function ( Group $pools , Cache $cache ) {
$dbAdapter = $pools
-> get ( 'console' )
-> pop ()
2023-11-22 08:32:36 +00:00
-> getResource ();
2021-05-04 09:31:26 +00:00
2022-10-15 08:52:50 +00:00
$database = new Database ( $dbAdapter , $cache );
2021-05-04 09:31:26 +00:00
2023-10-19 02:32:45 +00:00
$database
-> setNamespace ( '_console' )
2023-10-18 03:21:10 +00:00
-> setMetadata ( 'host' , \gethostname ())
2023-10-26 09:28:23 +00:00
-> setMetadata ( 'project' , 'console' )
2024-10-15 12:50:02 +00:00
-> setTimeout ( APP_DATABASE_TIMEOUT_MILLISECONDS )
2024-10-16 08:35:32 +00:00
-> setMaxQueryValues ( APP_DATABASE_QUERY_MAX_VALUES );
2021-05-04 09:31:26 +00:00
return $database ;
2022-10-15 08:52:50 +00:00
}, [ 'pools' , 'cache' ]);
2022-07-27 16:59:27 +00:00
2023-05-23 04:37:25 +00:00
App :: setResource ( 'getProjectDB' , function ( Group $pools , Database $dbForConsole , $cache ) {
$databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools
2023-11-22 12:13:24 +00:00
return function ( Document $project ) use ( $pools , $dbForConsole , $cache , & $databases ) {
2023-05-23 04:37:25 +00:00
if ( $project -> isEmpty () || $project -> getId () === 'console' ) {
return $dbForConsole ;
}
2024-05-06 06:13:41 +00:00
try {
$dsn = new DSN ( $project -> getAttribute ( 'database' ));
} catch ( \InvalidArgumentException ) {
2024-05-07 02:07:04 +00:00
// TODO: Temporary until all projects are using shared tables
2024-05-06 06:13:41 +00:00
$dsn = new DSN ( 'mysql://' . $project -> getAttribute ( 'database' ));
}
2023-10-19 04:21:11 +00:00
2024-05-06 05:33:36 +00:00
$configure = ( function ( Database $database ) use ( $project , $dsn ) {
2023-10-19 04:21:11 +00:00
$database
2023-10-25 05:21:16 +00:00
-> setMetadata ( 'host' , \gethostname ())
2023-10-26 09:28:23 +00:00
-> setMetadata ( 'project' , $project -> getId ())
2024-10-15 12:50:02 +00:00
-> setTimeout ( APP_DATABASE_TIMEOUT_MILLISECONDS )
2024-10-16 08:35:32 +00:00
-> setMaxQueryValues ( APP_DATABASE_QUERY_MAX_VALUES );
2023-10-19 04:21:11 +00:00
2024-10-20 07:56:44 +00:00
$sharedTables = \explode ( ',' , System :: getEnv ( '_APP_DATABASE_SHARED_TABLES' , '' ));
if ( \in_array ( $dsn -> getHost (), $sharedTables )) {
$database
2024-03-07 16:49:59 +00:00
-> setSharedTables ( true )
2023-11-27 11:26:35 +00:00
-> setTenant ( $project -> getInternalId ())
2024-05-06 05:33:36 +00:00
-> setNamespace ( $dsn -> getParam ( 'namespace' ));
2024-03-07 13:52:13 +00:00
} else {
$database
2024-03-07 16:49:59 +00:00
-> setSharedTables ( false )
2024-03-07 13:52:13 +00:00
-> setTenant ( null )
-> setNamespace ( '_' . $project -> getInternalId ());
}
2023-11-22 12:13:24 +00:00
});
2024-05-06 06:13:41 +00:00
if ( isset ( $databases [ $dsn -> getHost ()])) {
$database = $databases [ $dsn -> getHost ()];
2023-11-22 12:13:24 +00:00
$configure ( $database );
2023-05-23 04:37:25 +00:00
return $database ;
}
$dbAdapter = $pools
2024-05-06 06:13:41 +00:00
-> get ( $dsn -> getHost ())
2023-05-23 04:37:25 +00:00
-> pop ()
-> getResource ();
$database = new Database ( $dbAdapter , $cache );
2024-05-06 06:13:41 +00:00
$databases [ $dsn -> getHost ()] = $database ;
2023-11-22 12:13:24 +00:00
$configure ( $database );
2023-05-23 04:37:25 +00:00
return $database ;
};
}, [ 'pools' , 'dbForConsole' , 'cache' ]);
2022-10-15 14:14:17 +00:00
App :: setResource ( 'cache' , function ( Group $pools ) {
2022-10-16 11:42:00 +00:00
$list = Config :: getParam ( 'pools-cache' , []);
$adapters = [];
2022-10-19 08:35:30 +00:00
2022-10-16 11:42:00 +00:00
foreach ( $list as $value ) {
$adapters [] = $pools
-> get ( $value )
-> pop ()
-> getResource ()
;
}
2021-05-04 09:31:26 +00:00
2022-10-16 11:42:00 +00:00
return new Cache ( new Sharding ( $adapters ));
2022-10-15 14:14:17 +00:00
}, [ 'pools' ]);
2022-01-07 10:02:38 +00:00
2024-02-20 14:10:51 +00:00
App :: setResource ( 'deviceForLocal' , function () {
2021-12-13 07:34:15 +00:00
return new Local ();
});
2024-10-31 15:43:49 +00:00
App :: setResource ( 'deviceForFiles' , function ( $project ) {
return getDevice ( APP_STORAGE_UPLOADS . '/app-' . $project -> getId ());
}, [ 'project' ]);
2024-09-15 15:40:55 +00:00
2024-10-31 15:43:49 +00:00
App :: setResource ( 'deviceForFunctions' , function ( $project ) {
return getDevice ( APP_STORAGE_FUNCTIONS . '/app-' . $project -> getId ());
}, [ 'project' ]);
2021-12-13 07:34:15 +00:00
2024-10-31 15:43:49 +00:00
App :: setResource ( 'deviceForBuilds' , function ( $project ) {
return getDevice ( APP_STORAGE_BUILDS . '/app-' . $project -> getId ());
}, [ 'project' ]);
2024-09-15 15:40:55 +00:00
2024-10-31 15:43:49 +00:00
function getDevice ( string $root , string $connection = '' ) : Device
2022-05-23 14:54:50 +00:00
{
2024-10-31 15:43:49 +00:00
$connection = ! empty ( $connection ) ? $connection : System :: getEnv ( '_APP_CONNECTIONS_STORAGE' , '' );
2022-10-26 06:46:22 +00:00
2024-10-31 15:43:49 +00:00
if ( ! empty ( $connection )) {
2023-08-23 10:08:48 +00:00
$acl = 'private' ;
$device = Storage :: DEVICE_LOCAL ;
$accessKey = '' ;
$accessSecret = '' ;
$bucket = '' ;
$region = '' ;
try {
2024-10-31 15:43:49 +00:00
$dsn = new DSN ( $connection );
2023-08-23 10:08:48 +00:00
$device = $dsn -> getScheme ();
2023-08-23 11:52:17 +00:00
$accessKey = $dsn -> getUser () ? ? '' ;
$accessSecret = $dsn -> getPassword () ? ? '' ;
$bucket = $dsn -> getPath () ? ? '' ;
2023-08-23 10:08:48 +00:00
$region = $dsn -> getParam ( 'region' );
2024-02-08 01:17:54 +00:00
} catch ( \Throwable $e ) {
2023-08-23 11:52:17 +00:00
Console :: warning ( $e -> getMessage () . 'Invalid DSN. Defaulting to Local device.' );
2023-08-23 10:08:48 +00:00
}
2022-10-26 06:46:22 +00:00
2023-08-23 10:08:48 +00:00
switch ( $device ) {
case Storage :: DEVICE_S3 :
return new S3 ( $root , $accessKey , $accessSecret , $bucket , $region , $acl );
case STORAGE :: DEVICE_DO_SPACES :
2024-04-02 08:35:14 +00:00
$device = new DOSpaces ( $root , $accessKey , $accessSecret , $bucket , $region , $acl );
$device -> setHttpVersion ( S3 :: HTTP_VERSION_1_1 );
return $device ;
2023-08-23 10:08:48 +00:00
case Storage :: DEVICE_BACKBLAZE :
return new Backblaze ( $root , $accessKey , $accessSecret , $bucket , $region , $acl );
case Storage :: DEVICE_LINODE :
return new Linode ( $root , $accessKey , $accessSecret , $bucket , $region , $acl );
case Storage :: DEVICE_WASABI :
return new Wasabi ( $root , $accessKey , $accessSecret , $bucket , $region , $acl );
case Storage :: DEVICE_LOCAL :
default :
return new Local ( $root );
}
} else {
2024-04-01 11:02:47 +00:00
switch ( strtolower ( System :: getEnv ( '_APP_STORAGE_DEVICE' , Storage :: DEVICE_LOCAL ) ? ? '' )) {
2023-08-23 10:08:48 +00:00
case Storage :: DEVICE_LOCAL :
default :
return new Local ( $root );
case Storage :: DEVICE_S3 :
2024-04-01 11:02:47 +00:00
$s3AccessKey = System :: getEnv ( '_APP_STORAGE_S3_ACCESS_KEY' , '' );
$s3SecretKey = System :: getEnv ( '_APP_STORAGE_S3_SECRET' , '' );
$s3Region = System :: getEnv ( '_APP_STORAGE_S3_REGION' , '' );
$s3Bucket = System :: getEnv ( '_APP_STORAGE_S3_BUCKET' , '' );
2023-08-23 10:08:48 +00:00
$s3Acl = 'private' ;
return new S3 ( $root , $s3AccessKey , $s3SecretKey , $s3Bucket , $s3Region , $s3Acl );
case Storage :: DEVICE_DO_SPACES :
2024-04-01 11:02:47 +00:00
$doSpacesAccessKey = System :: getEnv ( '_APP_STORAGE_DO_SPACES_ACCESS_KEY' , '' );
$doSpacesSecretKey = System :: getEnv ( '_APP_STORAGE_DO_SPACES_SECRET' , '' );
$doSpacesRegion = System :: getEnv ( '_APP_STORAGE_DO_SPACES_REGION' , '' );
$doSpacesBucket = System :: getEnv ( '_APP_STORAGE_DO_SPACES_BUCKET' , '' );
2023-08-23 10:08:48 +00:00
$doSpacesAcl = 'private' ;
2024-04-02 08:35:14 +00:00
$device = new DOSpaces ( $root , $doSpacesAccessKey , $doSpacesSecretKey , $doSpacesBucket , $doSpacesRegion , $doSpacesAcl );
$device -> setHttpVersion ( S3 :: HTTP_VERSION_1_1 );
return $device ;
2023-08-23 10:08:48 +00:00
case Storage :: DEVICE_BACKBLAZE :
2024-04-01 11:02:47 +00:00
$backblazeAccessKey = System :: getEnv ( '_APP_STORAGE_BACKBLAZE_ACCESS_KEY' , '' );
$backblazeSecretKey = System :: getEnv ( '_APP_STORAGE_BACKBLAZE_SECRET' , '' );
$backblazeRegion = System :: getEnv ( '_APP_STORAGE_BACKBLAZE_REGION' , '' );
$backblazeBucket = System :: getEnv ( '_APP_STORAGE_BACKBLAZE_BUCKET' , '' );
2023-08-23 10:08:48 +00:00
$backblazeAcl = 'private' ;
return new Backblaze ( $root , $backblazeAccessKey , $backblazeSecretKey , $backblazeBucket , $backblazeRegion , $backblazeAcl );
case Storage :: DEVICE_LINODE :
2024-04-01 11:02:47 +00:00
$linodeAccessKey = System :: getEnv ( '_APP_STORAGE_LINODE_ACCESS_KEY' , '' );
$linodeSecretKey = System :: getEnv ( '_APP_STORAGE_LINODE_SECRET' , '' );
$linodeRegion = System :: getEnv ( '_APP_STORAGE_LINODE_REGION' , '' );
$linodeBucket = System :: getEnv ( '_APP_STORAGE_LINODE_BUCKET' , '' );
2023-08-23 10:08:48 +00:00
$linodeAcl = 'private' ;
return new Linode ( $root , $linodeAccessKey , $linodeSecretKey , $linodeBucket , $linodeRegion , $linodeAcl );
case Storage :: DEVICE_WASABI :
2024-04-01 11:02:47 +00:00
$wasabiAccessKey = System :: getEnv ( '_APP_STORAGE_WASABI_ACCESS_KEY' , '' );
$wasabiSecretKey = System :: getEnv ( '_APP_STORAGE_WASABI_SECRET' , '' );
$wasabiRegion = System :: getEnv ( '_APP_STORAGE_WASABI_REGION' , '' );
$wasabiBucket = System :: getEnv ( '_APP_STORAGE_WASABI_BUCKET' , '' );
2023-08-23 10:08:48 +00:00
$wasabiAcl = 'private' ;
return new Wasabi ( $root , $wasabiAccessKey , $wasabiSecretKey , $wasabiBucket , $wasabiRegion , $wasabiAcl );
}
2021-12-13 07:34:15 +00:00
}
2022-02-17 08:26:24 +00:00
}
2021-12-13 07:34:15 +00:00
2022-05-23 14:54:50 +00:00
App :: setResource ( 'mode' , function ( $request ) {
2021-12-31 15:50:07 +00:00
/** @var Appwrite\Utopia\Request $request */
2021-12-14 11:15:00 +00:00
/**
* Defines the mode for the request :
* - 'default' => Requests for Client and Server Side
* - 'admin' => Request from the Console on non - console projects
*/
2020-11-18 22:08:45 +00:00
return $request -> getParam ( 'mode' , $request -> getHeader ( 'x-appwrite-mode' , APP_MODE_DEFAULT ));
2020-06-30 18:08:02 +00:00
}, [ 'request' ]);
2020-07-02 20:24:14 +00:00
2022-05-23 14:54:50 +00:00
App :: setResource ( 'geodb' , function ( $register ) {
2020-10-29 15:54:36 +00:00
/** @var Utopia\Registry\Registry $register */
2020-10-29 14:08:09 +00:00
return $register -> get ( 'geodb' );
2020-10-29 15:54:36 +00:00
}, [ 'register' ]);
2022-06-08 09:00:38 +00:00
2022-12-26 09:19:06 +00:00
App :: setResource ( 'passwordsDictionary' , function ( $register ) {
2022-12-23 07:19:11 +00:00
/** @var Utopia\Registry\Registry $register */
2022-12-26 09:24:51 +00:00
return $register -> get ( 'passwordsDictionary' );
2022-12-23 07:19:11 +00:00
}, [ 'register' ]);
2022-08-10 13:45:04 +00:00
App :: setResource ( 'servers' , function () {
$platforms = Config :: getParam ( 'platforms' );
$server = $platforms [ APP_PLATFORM_SERVER ];
$languages = array_map ( function ( $language ) {
return strtolower ( $language [ 'name' ]);
2023-05-23 13:43:03 +00:00
}, $server [ 'sdks' ]);
2022-08-10 13:45:04 +00:00
return $languages ;
2022-08-10 13:49:56 +00:00
});
2023-05-23 13:43:03 +00:00
App :: setResource ( 'promiseAdapter' , function ( $register ) {
return $register -> get ( 'promiseAdapter' );
}, [ 'register' ]);
App :: setResource ( 'schema' , function ( $utopia , $dbForProject ) {
$complexity = function ( int $complexity , array $args ) {
$queries = Query :: parseQueries ( $args [ 'queries' ] ? ? []);
2023-05-01 09:18:50 +00:00
$query = Query :: getByType ( $queries , [ Query :: TYPE_LIMIT ])[ 0 ] ? ? null ;
2023-05-23 13:43:03 +00:00
$limit = $query ? $query -> getValue () : APP_LIMIT_LIST_DEFAULT ;
return $complexity * $limit ;
};
$attributes = function ( int $limit , int $offset ) use ( $dbForProject ) {
2024-03-06 17:34:21 +00:00
$attrs = Authorization :: skip ( fn () => $dbForProject -> find ( 'attributes' , [
2023-05-23 13:43:03 +00:00
Query :: limit ( $limit ),
Query :: offset ( $offset ),
]));
return \array_map ( function ( $attr ) {
return $attr -> getArrayCopy ();
}, $attrs );
};
$urls = [
'list' => function ( string $databaseId , string $collectionId , array $args ) {
return " /v1/databases/ $databaseId /collections/ $collectionId /documents " ;
},
'create' => function ( string $databaseId , string $collectionId , array $args ) {
return " /v1/databases/ $databaseId /collections/ $collectionId /documents " ;
},
'read' => function ( string $databaseId , string $collectionId , array $args ) {
return " /v1/databases/ $databaseId /collections/ $collectionId /documents/ { $args [ 'documentId' ] } " ;
},
'update' => function ( string $databaseId , string $collectionId , array $args ) {
return " /v1/databases/ $databaseId /collections/ $collectionId /documents/ { $args [ 'documentId' ] } " ;
},
'delete' => function ( string $databaseId , string $collectionId , array $args ) {
return " /v1/databases/ $databaseId /collections/ $collectionId /documents/ { $args [ 'documentId' ] } " ;
},
];
$params = [
'list' => function ( string $databaseId , string $collectionId , array $args ) {
return [ 'queries' => $args [ 'queries' ]];
},
'create' => function ( string $databaseId , string $collectionId , array $args ) {
$id = $args [ 'id' ] ? ? 'unique()' ;
$permissions = $args [ 'permissions' ] ? ? null ;
unset ( $args [ 'id' ]);
unset ( $args [ 'permissions' ]);
// Order must be the same as the route params
return [
'databaseId' => $databaseId ,
'documentId' => $id ,
'collectionId' => $collectionId ,
'data' => $args ,
'permissions' => $permissions ,
];
},
'update' => function ( string $databaseId , string $collectionId , array $args ) {
$documentId = $args [ 'id' ];
$permissions = $args [ 'permissions' ] ? ? null ;
unset ( $args [ 'id' ]);
unset ( $args [ 'permissions' ]);
// Order must be the same as the route params
return [
'databaseId' => $databaseId ,
'collectionId' => $collectionId ,
'documentId' => $documentId ,
'data' => $args ,
'permissions' => $permissions ,
];
},
];
return Schema :: build (
$utopia ,
$complexity ,
$attributes ,
$urls ,
$params ,
);
}, [ 'utopia' , 'dbForProject' ]);
2023-07-10 03:06:48 +00:00
2023-04-26 08:21:10 +00:00
App :: setResource ( 'contributors' , function () {
2023-08-29 18:25:00 +00:00
$path = 'app/config/contributors.json' ;
2023-04-26 08:21:10 +00:00
$list = ( file_exists ( $path )) ? json_decode ( file_get_contents ( $path ), true ) : [];
return $list ;
2023-08-29 18:25:00 +00:00
});
2023-04-26 08:21:10 +00:00
App :: setResource ( 'employees' , function () {
2023-08-29 18:25:00 +00:00
$path = 'app/config/employees.json' ;
2023-04-26 08:21:10 +00:00
$list = ( file_exists ( $path )) ? json_decode ( file_get_contents ( $path ), true ) : [];
return $list ;
2023-08-29 18:25:00 +00:00
});
2023-04-26 08:21:10 +00:00
App :: setResource ( 'heroes' , function () {
2023-08-29 18:25:00 +00:00
$path = 'app/config/heroes.json' ;
2023-04-26 08:21:10 +00:00
$list = ( file_exists ( $path )) ? json_decode ( file_get_contents ( $path ), true ) : [];
return $list ;
2023-08-29 18:25:00 +00:00
});
2023-05-26 08:44:08 +00:00
App :: setResource ( 'gitHub' , function ( Cache $cache ) {
return new VcsGitHub ( $cache );
}, [ 'cache' ]);
2023-08-06 07:31:32 +00:00
2023-01-20 00:36:17 +00:00
App :: setResource ( 'requestTimestamp' , function ( $request ) {
2023-04-11 14:59:45 +00:00
//TODO: Move this to the Request class itself
2023-01-20 00:36:17 +00:00
$timestampHeader = $request -> getHeader ( 'x-appwrite-timestamp' );
$requestTimestamp = null ;
if ( ! empty ( $timestampHeader )) {
try {
$requestTimestamp = new \DateTime ( $timestampHeader );
} catch ( \Throwable $e ) {
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , 'Invalid X-Appwrite-Timestamp header value' );
}
}
return $requestTimestamp ;
}, [ 'request' ]);
2024-10-17 11:32:42 +00:00
2024-03-19 10:15:39 +00:00
App :: setResource ( 'plan' , function ( array $plan = []) {
return [];
});
2024-09-04 02:16:18 +00:00
App :: setResource ( 'team' , function ( Document $project , Database $dbForConsole , App $utopia , Request $request ) {
$teamInternalId = '' ;
if ( $project -> getId () !== 'console' ) {
2024-09-04 23:48:51 +00:00
$teamInternalId = $project -> getAttribute ( 'teamInternalId' , '' );
2024-09-04 02:16:18 +00:00
} else {
$route = $utopia -> match ( $request );
$path = $route -> getPath ();
if ( str_starts_with ( $path , '/v1/projects/:projectId' )) {
$uri = $request -> getURI ();
$pid = explode ( '/' , $uri )[ 3 ];
2024-09-04 02:40:53 +00:00
$p = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'projects' , $pid ));
2024-09-04 02:16:18 +00:00
$teamInternalId = $p -> getAttribute ( 'teamInternalId' , '' );
2024-09-05 02:47:50 +00:00
} elseif ( $path === '/v1/projects' ) {
$teamId = $request -> getParam ( 'teamId' , '' );
$team = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'teams' , $teamId ));
return $team ;
2024-09-04 02:16:18 +00:00
}
}
$team = Authorization :: skip ( function () use ( $dbForConsole , $teamInternalId ) {
return $dbForConsole -> findOne ( 'teams' , [
Query :: equal ( '$internalId' , [ $teamInternalId ]),
]);
});
return $team ;
}, [ 'project' , 'dbForConsole' , 'utopia' , 'request' ]);
2024-10-17 11:32:42 +00:00
App :: setResource (
'isResourceBlocked' ,
fn () => fn ( Document $project , string $resourceType , ? string $resourceId ) => false
);
2024-11-06 10:52:43 +00:00
2024-11-06 16:05:58 +00:00
App :: setResource ( 'previewHostname' , function ( Request $request ) {
2024-11-06 10:52:43 +00:00
if ( App :: isDevelopment ()) {
2024-11-06 16:05:58 +00:00
$host = $request -> getQuery ( 'appwrite-hostname' ) ? ? '' ;
2024-11-06 10:52:43 +00:00
if ( ! empty ( $host )) {
return $host ;
}
}
return '' ;
}, [ 'request' ]);