2019-05-09 18:54:39 +12:00
|
|
|
<?php
|
|
|
|
|
2020-07-29 19:29:34 +12:00
|
|
|
require_once __DIR__.'/../init.php';
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2019-05-09 18:54:39 +12:00
|
|
|
use Utopia\App;
|
2020-08-15 23:39:44 +12:00
|
|
|
use Utopia\Swoole\Request;
|
2020-06-29 19:22:53 +12:00
|
|
|
use Appwrite\Utopia\Response;
|
2019-10-25 06:53:37 +13:00
|
|
|
use Utopia\View;
|
|
|
|
use Utopia\Exception;
|
2020-03-29 01:42:16 +13:00
|
|
|
use Utopia\Config\Config;
|
2020-03-18 00:36:13 +13:00
|
|
|
use Utopia\Domains\Domain;
|
2020-03-25 06:56:32 +13:00
|
|
|
use Appwrite\Auth\Auth;
|
2020-06-12 07:36:10 +12:00
|
|
|
use Appwrite\Network\Validator\Origin;
|
2021-01-10 11:29:49 +13:00
|
|
|
use Appwrite\Utopia\Response\Filters\V06;
|
2021-05-15 03:15:29 +12:00
|
|
|
use Appwrite\Utopia\Response\Filters\V07;
|
2021-07-02 01:35:36 +12:00
|
|
|
use Appwrite\Utopia\Response\Filters\V08;
|
2020-10-30 11:04:53 +13:00
|
|
|
use Utopia\CLI\Console;
|
2021-05-16 21:18:34 +12:00
|
|
|
use Utopia\Database\Document;
|
2021-07-16 09:14:52 +12:00
|
|
|
use Utopia\Database\Query;
|
2021-07-26 02:51:04 +12:00
|
|
|
use Utopia\Database\Validator\Authorization;
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2020-06-29 08:45:36 +12:00
|
|
|
Config::setParam('domainVerification', false);
|
2020-07-01 18:35:57 +12:00
|
|
|
Config::setParam('cookieDomain', 'localhost');
|
|
|
|
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
|
2020-06-30 09:43:34 +12:00
|
|
|
|
2021-07-16 09:14:52 +12:00
|
|
|
App::init(function ($utopia, $request, $response, $console, $project, $dbForConsole, $user, $locale, $clients) {
|
2020-08-15 23:39:44 +12:00
|
|
|
/** @var Utopia\Swoole\Request $request */
|
2020-08-15 09:56:33 +12:00
|
|
|
/** @var Appwrite\Utopia\Response $response */
|
2021-07-16 09:14:52 +12:00
|
|
|
/** @var Utopia\Database\Database $dbForConsole */
|
2021-05-16 21:18:34 +12:00
|
|
|
/** @var Utopia\Database\Document $console */
|
2021-05-16 10:41:42 +12:00
|
|
|
/** @var Utopia\Database\Document $project */
|
|
|
|
/** @var Utopia\Database\Document $user */
|
2020-06-30 23:09:28 +12:00
|
|
|
/** @var Utopia\Locale\Locale $locale */
|
|
|
|
/** @var array $clients */
|
2021-05-16 10:41:42 +12:00
|
|
|
|
2021-05-11 22:47:02 +12:00
|
|
|
$domain = $request->getHostname();
|
2021-05-12 17:19:48 +12:00
|
|
|
$domains = Config::getParam('domains', []);
|
|
|
|
if (!array_key_exists($domain, $domains)) {
|
2021-05-11 22:47:02 +12:00
|
|
|
$domain = new Domain(!empty($domain) ? $domain : '');
|
|
|
|
|
2021-05-11 23:15:26 +12:00
|
|
|
if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) {
|
2021-05-12 17:19:48 +12:00
|
|
|
$domains[$domain->get()] = false;
|
2021-05-12 17:17:34 +12:00
|
|
|
Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
2021-05-11 22:47:02 +12:00
|
|
|
} else {
|
2021-07-26 02:51:04 +12:00
|
|
|
Authorization::disable();
|
2021-05-11 22:47:02 +12:00
|
|
|
|
2021-08-04 08:22:03 +12:00
|
|
|
$certificate = $dbForConsole->findOne('certificates', [
|
2021-07-16 09:14:52 +12:00
|
|
|
new Query('domain', QUERY::TYPE_EQUAL, [$domain->get()])
|
2021-08-04 08:22:03 +12:00
|
|
|
]);
|
2021-07-16 09:14:52 +12:00
|
|
|
|
|
|
|
if (empty($certificate)) {
|
|
|
|
$certificate = new Document([
|
2021-05-11 22:47:02 +12:00
|
|
|
'domain' => $domain->get(),
|
2021-07-16 09:14:52 +12:00
|
|
|
]);
|
|
|
|
$certificate = $dbForConsole->createDocument('certificates', $certificate);
|
2021-07-26 02:51:04 +12:00
|
|
|
Authorization::enable();
|
2021-05-11 22:47:02 +12:00
|
|
|
|
2021-07-16 16:39:31 +12:00
|
|
|
Console::info('Issuing a TLS certificate for the master domain (' . $domain->get() . ') in a few seconds...');
|
2021-05-11 22:47:02 +12:00
|
|
|
|
2021-05-19 01:10:09 +12:00
|
|
|
Resque::enqueue('v1-certificates', 'CertificatesV1', [
|
2021-07-16 09:14:52 +12:00
|
|
|
'document' => $certificate,
|
2021-05-11 22:47:02 +12:00
|
|
|
'domain' => $domain->get(),
|
|
|
|
'validateTarget' => false,
|
|
|
|
'validateCNAME' => false,
|
|
|
|
]);
|
2021-07-16 09:14:52 +12:00
|
|
|
} else {
|
2021-07-26 02:51:04 +12:00
|
|
|
Authorization::enable(); // ensure authorization is reenabled
|
2021-05-11 22:47:02 +12:00
|
|
|
}
|
2021-05-12 17:19:48 +12:00
|
|
|
$domains[$domain->get()] = true;
|
2021-05-11 22:47:02 +12:00
|
|
|
}
|
2021-05-12 17:19:48 +12:00
|
|
|
Config::setParam('domains', $domains);
|
2021-05-11 22:47:02 +12:00
|
|
|
}
|
2020-06-30 23:09:28 +12:00
|
|
|
|
2020-07-05 10:22:22 +12:00
|
|
|
$localeParam = (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', ''));
|
2020-06-30 17:27:52 +12:00
|
|
|
|
|
|
|
if (\in_array($localeParam, Config::getParam('locale-codes'))) {
|
2020-06-30 09:43:34 +12:00
|
|
|
$locale->setDefault($localeParam);
|
|
|
|
};
|
2019-10-25 06:53:37 +13:00
|
|
|
|
|
|
|
$route = $utopia->match($request);
|
|
|
|
|
2021-05-17 21:37:48 +12:00
|
|
|
if ($project->isEmpty()) {
|
|
|
|
throw new Exception('Project not found', 404);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) {
|
2020-04-08 23:21:41 +12:00
|
|
|
throw new Exception('Missing or unknown project ID', 400);
|
2020-04-07 18:10:58 +12:00
|
|
|
}
|
|
|
|
|
2020-07-03 09:48:02 +12:00
|
|
|
$referrer = $request->getReferer();
|
|
|
|
$origin = \parse_url($request->getOrigin($referrer), PHP_URL_HOST);
|
|
|
|
$protocol = \parse_url($request->getOrigin($referrer), PHP_URL_SCHEME);
|
|
|
|
$port = \parse_url($request->getOrigin($referrer), PHP_URL_PORT);
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2020-07-21 17:48:31 +12:00
|
|
|
$refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()).'://'.((\in_array($origin, $clients))
|
2021-01-18 19:58:48 +13:00
|
|
|
? $origin : 'localhost').(!empty($port) ? ':'.$port : '');
|
|
|
|
|
|
|
|
$refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible
|
|
|
|
? $refDomain
|
|
|
|
: (!empty($protocol) ? $protocol : $request->getProtocol()).'://'.$origin.(!empty($port) ? ':'.$port : '');
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2020-07-03 09:48:02 +12:00
|
|
|
$selfDomain = new Domain($request->getHostname());
|
2020-10-27 13:08:29 +13:00
|
|
|
$endDomain = new Domain((string)$origin);
|
2020-03-18 00:36:13 +13:00
|
|
|
|
2020-07-03 09:48:02 +12:00
|
|
|
// var_dump('referer', $referrer);
|
|
|
|
// var_dump('origin', $origin);
|
2020-07-03 05:37:24 +12:00
|
|
|
// var_dump('port', $request->getPort());
|
|
|
|
// var_dump('hostname', $request->getHostname());
|
|
|
|
// var_dump('protocol', $request->getProtocol());
|
|
|
|
// var_dump('method', $request->getMethod());
|
|
|
|
// var_dump('ip', $request->getIP());
|
|
|
|
// var_dump('-----------------');
|
|
|
|
// var_dump($request->debug());
|
|
|
|
|
2020-04-07 18:10:58 +12:00
|
|
|
Config::setParam('domainVerification',
|
2020-05-28 22:10:38 +12:00
|
|
|
($selfDomain->getRegisterable() === $endDomain->getRegisterable()) &&
|
|
|
|
$endDomain->getRegisterable() !== '');
|
2020-04-07 18:10:58 +12:00
|
|
|
|
2020-07-01 18:35:57 +12:00
|
|
|
Config::setParam('cookieDomain', (
|
2020-07-03 09:48:02 +12:00
|
|
|
$request->getHostname() === 'localhost' ||
|
|
|
|
$request->getHostname() === 'localhost:'.$request->getPort() ||
|
2020-07-01 18:35:57 +12:00
|
|
|
(\filter_var($request->getHostname(), FILTER_VALIDATE_IP) !== false)
|
|
|
|
)
|
|
|
|
? null
|
|
|
|
: '.'.$request->getHostname()
|
|
|
|
);
|
2020-07-03 09:48:02 +12:00
|
|
|
|
2020-12-30 08:07:33 +13:00
|
|
|
/*
|
2021-05-16 10:41:42 +12:00
|
|
|
* Response format
|
|
|
|
*/
|
2021-01-01 08:56:39 +13:00
|
|
|
$responseFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
|
2021-01-06 02:46:06 +13:00
|
|
|
if ($responseFormat) {
|
2021-01-03 04:35:21 +13:00
|
|
|
switch($responseFormat) {
|
2021-01-03 05:53:31 +13:00
|
|
|
case version_compare ($responseFormat , '0.6.2', '<=') :
|
2021-01-03 04:35:21 +13:00
|
|
|
Response::setFilter(new V06());
|
|
|
|
break;
|
2021-05-15 03:15:29 +12:00
|
|
|
case version_compare ($responseFormat , '0.7.2', '<=') :
|
|
|
|
Response::setFilter(new V07());
|
|
|
|
break;
|
2021-07-02 01:35:36 +12:00
|
|
|
case version_compare ($responseFormat , '0.8.0', '<=') :
|
|
|
|
Response::setFilter(new V08());
|
|
|
|
break;
|
2021-01-03 04:35:21 +13:00
|
|
|
default:
|
2021-02-10 19:07:49 +13:00
|
|
|
Response::setFilter(null);
|
2021-01-03 04:35:21 +13:00
|
|
|
}
|
2021-01-04 07:07:19 +13:00
|
|
|
} else {
|
|
|
|
Response::setFilter(null);
|
2020-12-30 08:07:33 +13:00
|
|
|
}
|
|
|
|
|
2019-10-25 06:53:37 +13:00
|
|
|
/*
|
|
|
|
* Security Headers
|
|
|
|
*
|
|
|
|
* As recommended at:
|
|
|
|
* @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
|
|
|
|
*/
|
2020-06-29 05:31:21 +12:00
|
|
|
if (App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
|
2020-10-28 08:46:15 +13:00
|
|
|
if ($request->getProtocol() !== 'https') {
|
|
|
|
return $response->redirect('https://'.$request->getHostname().$request->getURI());
|
2020-06-02 07:58:58 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
$response->addHeader('Strict-Transport-Security', 'max-age='.(60 * 60 * 24 * 126)); // 126 days
|
2021-01-18 19:49:24 +13:00
|
|
|
}
|
2020-06-02 07:58:58 +12:00
|
|
|
|
2019-10-25 06:53:37 +13:00
|
|
|
$response
|
|
|
|
->addHeader('Server', 'Appwrite')
|
|
|
|
->addHeader('X-Content-Type-Options', 'nosniff')
|
|
|
|
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
|
2021-03-05 19:36:41 +13:00
|
|
|
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, Cache-Control, Expires, Pragma')
|
2020-02-27 22:17:09 +13:00
|
|
|
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
|
2019-10-25 06:53:37 +13:00
|
|
|
->addHeader('Access-Control-Allow-Origin', $refDomain)
|
|
|
|
->addHeader('Access-Control-Allow-Credentials', 'true')
|
|
|
|
;
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2019-10-25 06:53:37 +13:00
|
|
|
/*
|
|
|
|
* Validate Client Domain - Check to avoid CSRF attack
|
|
|
|
* Adding Appwrite API domains to allow XDOMAIN communication
|
2021-01-06 01:22:20 +13:00
|
|
|
* Skip this check for non-web platforms which are not required to send an origin header
|
2019-10-25 06:53:37 +13:00
|
|
|
*/
|
2020-07-04 03:14:51 +12:00
|
|
|
$origin = $request->getOrigin($request->getReferer(''));
|
2020-06-20 23:20:49 +12:00
|
|
|
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
2020-04-14 17:44:15 +12:00
|
|
|
|
2020-10-28 08:46:15 +13:00
|
|
|
if (!$originValidator->isValid($origin)
|
2020-06-20 23:20:49 +12:00
|
|
|
&& \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE])
|
2020-05-30 00:02:53 +12:00
|
|
|
&& $route->getLabel('origin', false) !== '*'
|
2020-07-05 10:22:22 +12:00
|
|
|
&& empty($request->getHeader('x-appwrite-key', ''))) {
|
2020-10-28 08:46:15 +13:00
|
|
|
throw new Exception($originValidator->getDescription(), 403);
|
2019-10-25 06:53:37 +13:00
|
|
|
}
|
2020-04-14 17:44:15 +12:00
|
|
|
|
2019-10-25 06:53:37 +13:00
|
|
|
/*
|
|
|
|
* ACL Check
|
|
|
|
*/
|
|
|
|
$role = ($user->isEmpty()) ? Auth::USER_ROLE_GUEST : Auth::USER_ROLE_MEMBER;
|
|
|
|
|
|
|
|
// Add user roles
|
2021-05-16 22:55:12 +12:00
|
|
|
$memberships = $user->find('teamId', $project->getAttribute('teamId', null), 'memberships');
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2021-05-16 22:55:12 +12:00
|
|
|
if ($memberships) {
|
|
|
|
foreach ($memberships->getAttribute('roles', []) as $memberRole) {
|
2019-10-25 06:53:37 +13:00
|
|
|
switch ($memberRole) {
|
|
|
|
case 'owner':
|
|
|
|
$role = Auth::USER_ROLE_OWNER;
|
|
|
|
break;
|
|
|
|
case 'admin':
|
|
|
|
$role = Auth::USER_ROLE_ADMIN;
|
|
|
|
break;
|
|
|
|
case 'developer':
|
|
|
|
$role = Auth::USER_ROLE_DEVELOPER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2020-06-26 18:14:54 +12:00
|
|
|
$roles = Config::getParam('roles', []);
|
2019-10-25 06:53:37 +13:00
|
|
|
$scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route
|
|
|
|
$scopes = $roles[$role]['scopes']; // Allowed scopes for user role
|
2020-12-29 09:31:42 +13:00
|
|
|
|
2020-12-29 06:03:47 +13:00
|
|
|
$authKey = $request->getHeader('x-appwrite-key', '');
|
2020-12-29 09:31:42 +13:00
|
|
|
|
2020-12-29 06:03:47 +13:00
|
|
|
if (!empty($authKey)) { // API Key authentication
|
|
|
|
// Check if given key match project API keys
|
2021-05-16 10:41:42 +12:00
|
|
|
$key = $project->find('secret', $authKey, 'keys');
|
2020-12-29 06:03:47 +13:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try app auth when we have project key and no user
|
|
|
|
* Mock user to app and grant API key scopes in addition to default app scopes
|
|
|
|
*/
|
2020-12-29 23:45:44 +13:00
|
|
|
if ($key && $user->isEmpty()) {
|
2021-05-16 21:18:34 +12:00
|
|
|
$user = new Document([
|
2020-12-29 06:03:47 +13:00
|
|
|
'$id' => '',
|
2021-07-14 23:02:12 +12:00
|
|
|
'status' => true,
|
2020-12-29 06:03:47 +13:00
|
|
|
'email' => 'app.'.$project->getId().'@service.'.$request->getHostname(),
|
|
|
|
'password' => '',
|
|
|
|
'name' => $project->getAttribute('name', 'Untitled'),
|
|
|
|
]);
|
|
|
|
|
|
|
|
$role = Auth::USER_ROLE_APP;
|
|
|
|
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
|
|
|
|
|
2021-07-26 02:51:04 +12:00
|
|
|
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
|
2020-12-29 06:03:47 +13:00
|
|
|
}
|
2019-10-25 06:53:37 +13:00
|
|
|
}
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2020-10-30 11:44:01 +13:00
|
|
|
if ($user->getId()) {
|
2021-07-26 02:51:04 +12:00
|
|
|
Authorization::setRole('user:'.$user->getId());
|
2020-08-17 17:53:11 +12:00
|
|
|
}
|
2020-10-30 11:06:04 +13:00
|
|
|
|
2021-07-26 02:51:04 +12:00
|
|
|
Authorization::setRole('role:'.$role);
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2020-06-20 23:20:49 +12:00
|
|
|
\array_map(function ($node) {
|
2019-10-25 06:53:37 +13:00
|
|
|
if (isset($node['teamId']) && isset($node['roles'])) {
|
2021-07-26 02:51:04 +12:00
|
|
|
Authorization::setRole('team:'.$node['teamId']);
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2019-10-25 06:53:37 +13:00
|
|
|
foreach ($node['roles'] as $nodeRole) { // Set all team roles
|
2021-07-26 02:51:04 +12:00
|
|
|
Authorization::setRole('team:'.$node['teamId'].'/'.$nodeRole);
|
2019-10-25 06:53:37 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}, $user->getAttribute('memberships', []));
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2021-07-29 22:28:17 +12:00
|
|
|
$service = $route->getLabel('sdk.namespace','');
|
|
|
|
if(!empty($service)) {
|
2021-08-01 08:54:50 +12:00
|
|
|
if(array_key_exists($service, $project->getAttribute('services',[]))
|
|
|
|
&& !$project->getAttribute('services',[])[$service]
|
2021-07-29 22:28:17 +12:00
|
|
|
&& !Auth::isPrivilegedUser(Authorization::$roles)) {
|
|
|
|
throw new Exception('Service is disabled', 503);
|
|
|
|
}
|
|
|
|
}
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2020-06-20 23:20:49 +12:00
|
|
|
if (!\in_array($scope, $scopes)) {
|
2021-05-16 21:18:34 +12:00
|
|
|
if ($project->isEmpty()) { // Check if permission is denied because project is missing
|
2019-12-17 17:16:50 +13:00
|
|
|
throw new Exception('Project not found', 404);
|
|
|
|
}
|
|
|
|
|
2020-06-20 23:20:49 +12:00
|
|
|
throw new Exception($user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')', 401);
|
2019-10-25 06:53:37 +13:00
|
|
|
}
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2021-07-14 23:02:12 +12:00
|
|
|
if (false === $user->getAttribute('status')) { // Account is blocked
|
|
|
|
throw new Exception('Invalid credentials. User is blocked', 401);
|
2019-10-25 06:53:37 +13:00
|
|
|
}
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2019-10-25 06:53:37 +13:00
|
|
|
if ($user->getAttribute('reset')) {
|
|
|
|
throw new Exception('Password reset is required', 412);
|
|
|
|
}
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2021-07-17 01:33:30 +12:00
|
|
|
}, ['utopia', 'request', 'response', 'console', 'project', 'dbForConsole', 'user', 'locale', 'clients']);
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2020-06-30 09:43:34 +12:00
|
|
|
App::options(function ($request, $response) {
|
2020-08-15 23:39:44 +12:00
|
|
|
/** @var Utopia\Swoole\Request $request */
|
2020-08-15 09:56:33 +12:00
|
|
|
/** @var Appwrite\Utopia\Response $response */
|
2020-07-04 03:14:51 +12:00
|
|
|
|
2020-07-08 08:40:08 +12:00
|
|
|
$origin = $request->getOrigin();
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2019-10-25 06:53:37 +13:00
|
|
|
$response
|
2020-07-08 08:40:08 +12:00
|
|
|
->addHeader('Server', 'Appwrite')
|
2019-10-25 06:53:37 +13:00
|
|
|
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
|
2021-03-05 19:36:41 +13:00
|
|
|
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
|
2020-02-27 22:17:09 +13:00
|
|
|
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
|
2019-10-25 06:53:37 +13:00
|
|
|
->addHeader('Access-Control-Allow-Origin', $origin)
|
|
|
|
->addHeader('Access-Control-Allow-Credentials', 'true')
|
2021-02-02 19:03:28 +13:00
|
|
|
->noContent();
|
2020-06-30 09:43:34 +12:00
|
|
|
}, ['request', 'response']);
|
|
|
|
|
2020-07-03 17:55:08 +12:00
|
|
|
App::error(function ($error, $utopia, $request, $response, $layout, $project) {
|
2020-06-30 09:43:34 +12:00
|
|
|
/** @var Exception $error */
|
2020-07-03 17:55:08 +12:00
|
|
|
/** @var Utopia\App $utopia */
|
2020-08-15 23:39:44 +12:00
|
|
|
/** @var Utopia\Swoole\Request $request */
|
2020-08-15 09:56:33 +12:00
|
|
|
/** @var Appwrite\Utopia\Response $response */
|
2020-07-03 17:55:08 +12:00
|
|
|
/** @var Utopia\View $layout */
|
2021-07-26 02:47:18 +12:00
|
|
|
/** @var Utopia\Database\Document $project */
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2021-07-13 04:15:21 +12:00
|
|
|
if ($error instanceof PDOException) {
|
2021-07-13 03:27:26 +12:00
|
|
|
throw $error;
|
|
|
|
}
|
|
|
|
|
2020-08-10 09:19:30 +12:00
|
|
|
$route = $utopia->match($request);
|
|
|
|
$template = ($route) ? $route->getLabel('error', null) : null;
|
|
|
|
|
2021-01-18 02:50:01 +13:00
|
|
|
if (php_sapi_name() === 'cli') {
|
2021-03-19 11:08:19 +13:00
|
|
|
Console::error('[Error] Timestamp: '.date('c', time()));
|
|
|
|
|
2021-01-18 02:50:01 +13:00
|
|
|
if($route) {
|
|
|
|
Console::error('[Error] Method: '.$route->getMethod());
|
|
|
|
Console::error('[Error] URL: '.$route->getURL());
|
|
|
|
}
|
|
|
|
|
2020-10-30 11:04:53 +13:00
|
|
|
Console::error('[Error] Type: '.get_class($error));
|
|
|
|
Console::error('[Error] Message: '.$error->getMessage());
|
|
|
|
Console::error('[Error] File: '.$error->getFile());
|
|
|
|
Console::error('[Error] Line: '.$error->getLine());
|
2020-07-07 16:40:18 +12:00
|
|
|
}
|
2020-07-05 00:31:26 +12:00
|
|
|
|
2020-06-30 23:09:28 +12:00
|
|
|
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
2020-03-29 01:42:16 +13:00
|
|
|
|
2021-03-01 10:22:03 +13:00
|
|
|
switch ($error->getCode()) { // Don't show 500 errors!
|
2019-10-25 06:53:37 +13:00
|
|
|
case 400: // Error allowed publicly
|
|
|
|
case 401: // Error allowed publicly
|
|
|
|
case 402: // Error allowed publicly
|
|
|
|
case 403: // Error allowed publicly
|
|
|
|
case 404: // Error allowed publicly
|
2020-01-04 10:01:09 +13:00
|
|
|
case 409: // Error allowed publicly
|
2019-10-25 06:53:37 +13:00
|
|
|
case 412: // Error allowed publicly
|
|
|
|
case 429: // Error allowed publicly
|
2021-03-01 10:22:03 +13:00
|
|
|
case 501: // Error allowed publicly
|
2021-07-29 22:56:25 +12:00
|
|
|
case 503: // Error allowed publicly
|
2019-10-25 06:53:37 +13:00
|
|
|
$code = $error->getCode();
|
|
|
|
$message = $error->getMessage();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$code = 500; // All other errors get the generic 500 server error status code
|
|
|
|
$message = 'Server Error';
|
|
|
|
}
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2020-07-02 21:02:43 +12:00
|
|
|
//$_SERVER = []; // Reset before reporting to error log to avoid keys being compromised
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2020-06-29 20:32:46 +12:00
|
|
|
$output = ((App::isDevelopment())) ? [
|
2019-10-25 06:53:37 +13:00
|
|
|
'message' => $error->getMessage(),
|
|
|
|
'code' => $error->getCode(),
|
|
|
|
'file' => $error->getFile(),
|
|
|
|
'line' => $error->getLine(),
|
|
|
|
'trace' => $error->getTrace(),
|
|
|
|
'version' => $version,
|
|
|
|
] : [
|
|
|
|
'message' => $message,
|
|
|
|
'code' => $code,
|
|
|
|
'version' => $version,
|
|
|
|
];
|
|
|
|
|
|
|
|
$response
|
|
|
|
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
|
|
|
|
->addHeader('Expires', '0')
|
|
|
|
->addHeader('Pragma', 'no-cache')
|
|
|
|
->setStatusCode($code)
|
2019-10-25 06:53:11 +13:00
|
|
|
;
|
2019-05-09 18:54:39 +12:00
|
|
|
|
2019-10-25 06:53:37 +13:00
|
|
|
if ($template) {
|
|
|
|
$comp = new View($template);
|
|
|
|
|
|
|
|
$comp
|
2021-07-18 06:59:54 +12:00
|
|
|
->setParam('development', App::isDevelopment())
|
2019-10-25 06:53:37 +13:00
|
|
|
->setParam('projectName', $project->getAttribute('name'))
|
|
|
|
->setParam('projectURL', $project->getAttribute('url'))
|
|
|
|
->setParam('message', $error->getMessage())
|
|
|
|
->setParam('code', $code)
|
2021-07-18 06:59:54 +12:00
|
|
|
->setParam('trace', $error->getTrace())
|
2019-10-25 06:53:37 +13:00
|
|
|
;
|
|
|
|
|
|
|
|
$layout
|
|
|
|
->setParam('title', $project->getAttribute('name').' - Error')
|
|
|
|
->setParam('description', 'No Description')
|
|
|
|
->setParam('body', $comp)
|
|
|
|
->setParam('version', $version)
|
|
|
|
->setParam('litespeed', false)
|
|
|
|
;
|
|
|
|
|
2020-07-09 21:11:10 +12:00
|
|
|
$response->html($layout->render());
|
2019-10-25 06:53:11 +13:00
|
|
|
}
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2021-07-26 02:47:18 +12:00
|
|
|
$response->dynamic(new Document($output),
|
2020-12-23 09:33:20 +13:00
|
|
|
$utopia->isDevelopment() ? Response::MODEL_ERROR_DEV : Response::MODEL_ERROR);
|
2020-07-03 17:55:08 +12:00
|
|
|
}, ['error', 'utopia', 'request', 'response', 'layout', 'project']);
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2020-06-29 05:31:21 +12:00
|
|
|
App::get('/manifest.json')
|
2019-10-25 06:53:37 +13:00
|
|
|
->desc('Progressive app manifest file')
|
|
|
|
->label('scope', 'public')
|
|
|
|
->label('docs', false)
|
2020-12-27 01:19:46 +13:00
|
|
|
->inject('response')
|
2020-06-30 09:43:34 +12:00
|
|
|
->action(function ($response) {
|
2020-08-15 09:56:33 +12:00
|
|
|
/** @var Appwrite\Utopia\Response $response */
|
2020-06-30 09:43:34 +12:00
|
|
|
|
|
|
|
$response->json([
|
|
|
|
'name' => APP_NAME,
|
|
|
|
'short_name' => APP_NAME,
|
|
|
|
'start_url' => '.',
|
|
|
|
'url' => 'https://appwrite.io/',
|
|
|
|
'display' => 'standalone',
|
|
|
|
'background_color' => '#fff',
|
|
|
|
'theme_color' => '#f02e65',
|
|
|
|
'description' => 'End to end backend server for frontend and mobile apps. 👩💻👨💻',
|
|
|
|
'icons' => [
|
|
|
|
[
|
|
|
|
'src' => 'images/favicon.png',
|
|
|
|
'sizes' => '256x256',
|
|
|
|
'type' => 'image/png',
|
2019-10-25 06:53:37 +13:00
|
|
|
],
|
2020-06-30 09:43:34 +12:00
|
|
|
],
|
|
|
|
]);
|
2020-12-27 01:19:46 +13:00
|
|
|
});
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2020-06-29 05:31:21 +12:00
|
|
|
App::get('/robots.txt')
|
2019-10-25 06:53:37 +13:00
|
|
|
->desc('Robots.txt File')
|
|
|
|
->label('scope', 'public')
|
|
|
|
->label('docs', false)
|
2020-12-27 01:19:46 +13:00
|
|
|
->inject('response')
|
2020-06-30 09:43:34 +12:00
|
|
|
->action(function ($response) {
|
2020-08-12 02:28:24 +12:00
|
|
|
$template = new View(__DIR__.'/../views/general/robots.phtml');
|
2020-06-30 09:43:34 +12:00
|
|
|
$response->text($template->render(false));
|
2020-12-27 01:19:46 +13:00
|
|
|
});
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2020-06-29 05:31:21 +12:00
|
|
|
App::get('/humans.txt')
|
2019-10-25 06:53:37 +13:00
|
|
|
->desc('Humans.txt File')
|
|
|
|
->label('scope', 'public')
|
|
|
|
->label('docs', false)
|
2020-12-27 01:19:46 +13:00
|
|
|
->inject('response')
|
2020-06-30 09:43:34 +12:00
|
|
|
->action(function ($response) {
|
2020-08-12 02:28:24 +12:00
|
|
|
$template = new View(__DIR__.'/../views/general/humans.phtml');
|
2020-06-30 09:43:34 +12:00
|
|
|
$response->text($template->render(false));
|
2020-12-27 01:19:46 +13:00
|
|
|
});
|
2019-10-25 06:53:37 +13:00
|
|
|
|
2020-06-29 05:31:21 +12:00
|
|
|
App::get('/.well-known/acme-challenge')
|
2020-02-19 11:13:18 +13:00
|
|
|
->desc('SSL Verification')
|
|
|
|
->label('scope', 'public')
|
|
|
|
->label('docs', false)
|
2020-12-27 01:19:46 +13:00
|
|
|
->inject('request')
|
|
|
|
->inject('response')
|
2020-06-30 09:43:34 +12:00
|
|
|
->action(function ($request, $response) {
|
|
|
|
$base = \realpath(APP_STORAGE_CERTIFICATES);
|
2021-02-03 03:48:07 +13:00
|
|
|
$path = \str_replace('/.well-known/acme-challenge/', '', $request->getURI());
|
2020-06-30 09:43:34 +12:00
|
|
|
$absolute = \realpath($base.'/.well-known/acme-challenge/'.$path);
|
2020-02-23 21:55:57 +13:00
|
|
|
|
2020-10-28 08:46:15 +13:00
|
|
|
if (!$base) {
|
2020-06-30 09:43:34 +12:00
|
|
|
throw new Exception('Storage error', 500);
|
|
|
|
}
|
2020-02-19 11:13:18 +13:00
|
|
|
|
2020-10-28 08:46:15 +13:00
|
|
|
if (!$absolute) {
|
2020-06-30 09:43:34 +12:00
|
|
|
throw new Exception('Unknown path', 404);
|
|
|
|
}
|
2020-02-23 21:55:57 +13:00
|
|
|
|
2020-10-28 08:46:15 +13:00
|
|
|
if (!\substr($absolute, 0, \strlen($base)) === $base) {
|
2020-06-30 09:43:34 +12:00
|
|
|
throw new Exception('Invalid path', 401);
|
|
|
|
}
|
2020-02-24 06:45:51 +13:00
|
|
|
|
2020-10-28 08:46:15 +13:00
|
|
|
if (!\file_exists($absolute)) {
|
2020-06-30 09:43:34 +12:00
|
|
|
throw new Exception('Unknown path', 404);
|
|
|
|
}
|
2020-02-23 21:55:57 +13:00
|
|
|
|
2020-06-30 09:43:34 +12:00
|
|
|
$content = @\file_get_contents($absolute);
|
2020-02-19 11:13:18 +13:00
|
|
|
|
2020-10-28 08:46:15 +13:00
|
|
|
if (!$content) {
|
2020-06-30 09:43:34 +12:00
|
|
|
throw new Exception('Failed to get contents', 500);
|
2020-02-19 11:13:18 +13:00
|
|
|
}
|
2020-06-30 09:43:34 +12:00
|
|
|
|
|
|
|
$response->text($content);
|
2020-12-27 01:19:46 +13:00
|
|
|
});
|
2020-02-19 11:13:18 +13:00
|
|
|
|
2020-07-29 19:29:34 +12:00
|
|
|
include_once __DIR__ . '/shared/api.php';
|
|
|
|
include_once __DIR__ . '/shared/web.php';
|
2020-06-26 07:53:36 +12:00
|
|
|
|
2020-10-28 08:46:15 +13:00
|
|
|
foreach (Config::getParam('services', []) as $service) {
|
2020-06-26 18:14:54 +12:00
|
|
|
include_once $service['controller'];
|
2021-05-12 17:17:34 +12:00
|
|
|
}
|