1
0
Fork 0
mirror of synced 2024-06-27 10:41:00 +12:00

Merge branch '0.8.x' of github.com:appwrite/appwrite into feat-newsletter-subscribe

This commit is contained in:
Damodar Lohani 2021-05-13 18:26:56 +05:45
commit a346f7ab2a
18 changed files with 158 additions and 37 deletions

3
.env
View file

@ -1,6 +1,9 @@
_APP_ENV=production
_APP_ENV=development
_APP_LOCALE=en
_APP_CONSOLE_WHITELIST_ROOT=disabled
_APP_CONSOLE_WHITELIST_EMAILS=
_APP_CONSOLE_WHITELIST_IPS=
_APP_SYSTEM_EMAIL_NAME=Appwrite
_APP_SYSTEM_EMAIL_ADDRESS=team@appwrite.io
_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=security@appwrite.io

View file

@ -1,7 +1,7 @@
# Version 0.8.0 (Not Released Yet)
## Features
- Refactoring SSL generation to work on every request so no domain environment variable is required for SSL generation (#1133)
- Added Anonymous Login ([RFC-010](https://github.com/appwrite/rfc/blob/main/010-anonymous-login.md), #914)
- Added events for functions and executions (#971)
- Added JWT support (#784)
@ -12,7 +12,7 @@
- Added option to disable anonymous login (need to merge and apply changed) (#947)
- Added option to disable JWT auth (#947)
- Added option to disable team invites (#947)
- Option to limit number of users (good for app launches + god account PR) (#947)
- Option to limit number of users (good for app launches + root account PR) (#947)
- Added 2 new endpoints to the projects API to allow new settings
- Enabled 501 errors (Not Implemented) from the error handler
- Added Python 3.9 as a new Cloud Functions runtime (#1044)

View file

@ -88,6 +88,13 @@ ENV _APP_SERVER=swoole \
_APP_DOMAIN_TARGET=localhost \
_APP_HOME=https://appwrite.io \
_APP_EDITION=community \
_APP_CONSOLE_WHITELIST_ROOT=enabled \
_APP_CONSOLE_WHITELIST_EMAILS= \
_APP_CONSOLE_WHITELIST_IPS= \
_APP_SYSTEM_EMAIL_NAME= \
_APP_SYSTEM_EMAIL_ADDRESS= \
_APP_SYSTEM_RESPONSE_FORMAT= \
_APP_SYSTEM_SECURITY_EMAIL_ADDRESS= \
_APP_OPTIONS_ABUSE=enabled \
_APP_OPTIONS_FORCE_HTTPS=disabled \
_APP_OPENSSL_KEY_V1=your-secret-key \

View file

@ -46,7 +46,7 @@ $collections = [
'legalTaxId' => '',
'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
'authWhitelistDomains' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_DOMAINS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_DOMAINS', null)) : [],
'usersAuthLimit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
],
Database::SYSTEM_COLLECTION_COLLECTIONS => [
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,

View file

@ -63,9 +63,17 @@ return [
'required' => true,
'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.\nYou can use the same value as used for the Appwrite hostname.',
],
[
'name' => '_APP_CONSOLE_WHITELIST_ROOT',
'description' => 'This option allows you to disable the creation of new users on the Appwrite console. When enabled only 1 user will be able to use the registration form. New users can be added by invting them to your project. By default this option is enabled.',
'introduction' => '0.8.0',
'default' => 'enabled',
'required' => false,
'question' => '',
],
[
'name' => '_APP_CONSOLE_WHITELIST_EMAILS',
'description' => 'This option allows you to limit creation of users to Appwrite console. This option is very useful for small teams or sole developers. To enable it, pass a list of allowed email addresses separated by a comma.',
'description' => 'This option allows you to limit creation of new users on the Appwrite console. This option is very useful for small teams or sole developers. To enable it, pass a list of allowed email addresses separated by a comma.',
'introduction' => '',
'default' => '',
'required' => false,

View file

@ -61,7 +61,6 @@ App::post('/v1/account')
if ('console' === $project->getId()) {
$whitlistEmails = $project->getAttribute('authWhitelistEmails');
$whitlistIPs = $project->getAttribute('authWhitelistIPs');
$whitlistDomains = $project->getAttribute('authWhitelistDomains');
if (!empty($whitlistEmails) && !\in_array($email, $whitlistEmails)) {
throw new Exception('Console registration is restricted to specific emails. Contact your administrator for more information.', 401);
@ -70,10 +69,6 @@ App::post('/v1/account')
if (!empty($whitlistIPs) && !\in_array($request->getIP(), $whitlistIPs)) {
throw new Exception('Console registration is restricted to specific IPs. Contact your administrator for more information.', 401);
}
if (!empty($whitlistDomains) && !\in_array(\substr(\strrchr($email, '@'), 1), $whitlistDomains)) {
throw new Exception('Console registration is restricted to specific domains. Contact your administrator for more information.', 401);
}
}
$limit = $project->getAttribute('usersAuthLimit', 0);

View file

@ -272,7 +272,7 @@ App::get('/v1/health/anti-virus')
App::get('/v1/health/stats') // Currently only used internally
->desc('Get System Stats')
->groups(['api', 'health'])
->label('scope', 'god')
->label('scope', 'root')
// ->label('sdk.auth', [APP_AUTH_TYPE_KEY])
// ->label('sdk.namespace', 'health')
// ->label('sdk.method', 'getStats')

View file

@ -612,7 +612,7 @@ App::delete('/v1/storage/files/:fileId')
// App::get('/v1/storage/files/:fileId/scan')
// ->desc('Scan Storage')
// ->groups(['api', 'storage'])
// ->label('scope', 'god')
// ->label('scope', 'root')
// ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
// ->label('sdk.namespace', 'storage')
// ->label('sdk.method', 'getFileScan')

View file

@ -14,8 +14,6 @@ use Appwrite\Database\Database;
use Appwrite\Database\Document;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Network\Validator\Origin;
use Utopia\Storage\Device\Local;
use Utopia\Storage\Storage;
use Appwrite\Utopia\Response\Filters\V06;
use Utopia\CLI\Console;
@ -23,15 +21,61 @@ Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
App::init(function ($utopia, $request, $response, $console, $project, $user, $locale, $clients) {
App::init(function ($utopia, $request, $response, $console, $project, $consoleDB, $user, $locale, $clients) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
/** @var Appwrite\Database\Document $console */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Document $user */
/** @var Utopia\Locale\Locale $locale */
/** @var bool $mode */
/** @var array $clients */
$domain = $request->getHostname();
$domains = Config::getParam('domains', []);
if (!array_key_exists($domain, $domains)) {
$domain = new Domain(!empty($domain) ? $domain : '');
if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) {
$domains[$domain->get()] = false;
Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.');
} else {
Authorization::disable();
$dbDomain = $consoleDB->getCollectionFirst([
'limit' => 1,
'offset' => 0,
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_CERTIFICATES,
'domain=' . $domain->get(),
],
]);
if (empty($dbDomain)) {
$dbDomain = [
'$collection' => Database::SYSTEM_COLLECTION_CERTIFICATES,
'$permissions' => [
'read' => [],
'write' => [],
],
'domain' => $domain->get(),
];
$dbDomain = $consoleDB->createDocument($dbDomain);
Authorization::enable();
Console::info('Issuing a TLS certificate for the master domain (' . $domain->get() . ') in ~30 seconds..'); // TODO move this to installation script
ResqueScheduler::enqueueAt(\time() + 30, 'v1-certificates', 'CertificatesV1', [
'document' => $dbDomain,
'domain' => $domain->get(),
'validateTarget' => false,
'validateCNAME' => false,
]);
}
$domains[$domain->get()] = true;
}
Config::setParam('domains', $domains);
}
$localeParam = (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', ''));
@ -208,7 +252,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
}
}, $user->getAttribute('memberships', []));
// TDOO Check if user is god
// TDOO Check if user is root
if (!\in_array($scope, $scopes)) {
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS !== $project->getCollection()) { // Check if permission is denied because project is missing
@ -226,7 +270,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
throw new Exception('Password reset is required', 412);
}
}, ['utopia', 'request', 'response', 'console', 'project', 'user', 'locale', 'clients']);
}, ['utopia', 'request', 'response', 'console', 'project', 'consoleDB', 'user', 'locale', 'clients']);
App::options(function ($request, $response) {
/** @var Utopia\Swoole\Request $request */
@ -424,4 +468,4 @@ include_once __DIR__ . '/shared/web.php';
foreach (Config::getParam('services', []) as $service) {
include_once $service['controller'];
}
}

View file

@ -1,5 +1,6 @@
<?php
use Appwrite\Database\Database;
use Appwrite\Specification\Format\OpenAPI3;
use Appwrite\Specification\Format\Swagger2;
use Appwrite\Specification\Specification;
@ -42,10 +43,38 @@ App::get('/')
->label('permission', 'public')
->label('scope', 'home')
->inject('response')
->action(function ($response) {
->inject('consoleDB')
->inject('project')
->action(function ($response, $consoleDB, $project) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
/** @var Appwrite\Database\Document $project */
$response->redirect('/auth/signin');
$response
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->addHeader('Expires', 0)
->addHeader('Pragma', 'no-cache')
;
if ('console' === $project->getId() || $project->isEmpty()) {
$whitlistRoot = App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled');
if($whitlistRoot !== 'disabled') {
$consoleDB->getCollection([ // Count users
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_USERS,
],
]);
$sum = $consoleDB->getSum();
if($sum !== 0) {
return $response->redirect('/auth/signin');
}
}
}
$response->redirect('/auth/signup');
});
App::get('/auth/signin')
@ -58,6 +87,10 @@ App::get('/auth/signin')
$page = new View(__DIR__.'/../../views/home/auth/signin.phtml');
$page
->setParam('root', App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled'))
;
$layout
->setParam('title', 'Sign In - '.APP_NAME)
->setParam('body', $page);
@ -72,6 +105,10 @@ App::get('/auth/signup')
/** @var Utopia\View $layout */
$page = new View(__DIR__.'/../../views/home/auth/signup.phtml');
$page
->setParam('root', App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled'))
;
$layout
->setParam('title', 'Sign Up - '.APP_NAME)
->setParam('body', $page);
@ -87,6 +124,10 @@ App::get('/auth/recovery')
$page = new View(__DIR__.'/../../views/home/auth/recovery.phtml');
$page
->setParam('smtpEnabled', (!empty(App::getEnv('_APP_SMTP_HOST'))))
;
$layout
->setParam('title', 'Password Recovery - '.APP_NAME)
->setParam('body', $page);

View file

@ -12,6 +12,8 @@ use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Domains\Domain;
// xdebug_start_trace('/tmp/trace');
@ -65,18 +67,6 @@ Files::load(__DIR__ . '/../public');
include __DIR__ . '/controllers/general.php';
$domain = App::getEnv('_APP_DOMAIN', '');
Console::info('Issuing a TLS certificate for the master domain ('.$domain.') in 30 seconds.
Make sure your domain points to your server IP or restart your Appwrite server to try again.'); // TODO move this to installation script
ResqueScheduler::enqueueAt(\time() + 30, 'v1-certificates', 'CertificatesV1', [
'document' => [],
'domain' => $domain,
'validateTarget' => false,
'validateCNAME' => false,
]);
$http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) {
$request = new Request($swooleRequest);
$response = new Response($swooleResponse);

View file

@ -61,12 +61,12 @@ $cli
Console::log('🟢 Abuse protection is enabled');
}
$authWhitelistRoot = App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', null);
$authWhitelistEmails = App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null);
$authWhitelistIPs = App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null);
$authWhitelistDomains = App::getEnv('_APP_CONSOLE_WHITELIST_DOMAINS', null);
if(empty($authWhitelistEmails)
&& empty($authWhitelistDomains)
if(empty($authWhitelistRoot)
&& empty($authWhitelistEmails)
&& empty($authWhitelistIPs)
) {
Console::log('🔴 Console access limits are disabled');

View file

@ -1,6 +1,6 @@
<?php
$home = $this->getParam('home', '');
$version = $this->getParam('version', '').'.'.APP_CACHE_BUSTER;
$version = $this->getParam('version', '') . '.' . APP_CACHE_BUSTER;
?>
<footer class="clear margin-top-large">
<ul class="copyright pull-start">
@ -12,6 +12,14 @@ $version = $this->getParam('version', '').'.'.APP_CACHE_BUSTER;
data-analytics-label="GitHub Link"
href="https://github.com/appwrite/appwrite" target="_blank" rel="noopener"><i class="icon-github-circled"></i> GitHub</a>
</li>
<li>
<a class="link-animation-enabled"
data-analytics
data-analytics-event="click"
data-analytics-category="console/footer"
data-analytics-label="Discord Link"
href="https://appwrite.io/discord" target="_blank" rel="noopener"><i class="icon-discord"></i> Discord</a>
</li>
<li>
<a class="link-animation-enabled"
data-analytics

View file

@ -1,3 +1,6 @@
<?php
$smtpEnabled = $this->getParam('smtpEnabled', false);
?>
<div class="zone medium">
<h1 class="zone xl margin-bottom-large margin-top">
Password Recovery
@ -25,7 +28,13 @@
<input name="url" type="hidden" data-ls-bind="{{env.ENDPOINT}}/auth/recovery/reset" />
<button type="submit" class="btn btn-primary"><i class="fa fa-sign-in"></i> Recover</button>
<?php if(!$smtpEnabled): ?>
<div class="box note padding-tiny warning margin-bottom text-align-center">
<i class="icon-warning"></i> SMTP connection is disabled. <a href="https://appwrite.io/docs/email-delivery" target="_blank" rel="noopener">Learn more <i class="icon-link-ext"></i></a>
</div>
<?php endif; ?>
<button type="submit" class="btn btn-primary"<?php if(!$smtpEnabled): ?> disabled<?php endif; ?>><i class="fa fa-sign-in"></i> Recover</button>
</form>
</div>

View file

@ -1,3 +1,6 @@
<?php
$root = ($this->getParam('root') !== 'disabled');
?>
<div class="zone medium"
data-service="account.get"
data-name="account"
@ -43,7 +46,7 @@
<br />
<div class="text-line-high-large text-align-center">
<a href="/auth/recovery">Forgot password?</a> or don't have an account? <b><a href="/auth/signup">Sign up now</a></b>
<a href="/auth/recovery">Forgot password?</a><?php if(!$root): ?> or don't have an account? <b><a href="/auth/signup">Sign up now</a></b><?php endif; ?>
</div>
</div>

View file

@ -1,3 +1,6 @@
<?php
$root = ($this->getParam('root') !== 'disabled');
?>
<div class="zone medium signup">
<h1 class="zone xl margin-bottom-large margin-top">
Sign Up
@ -24,6 +27,10 @@
data-failure-param-alert-text="Registration Failed. Please try again later"
data-failure-param-alert-classname="error">
<?php if($root): ?>
<p>Please create your root account</p>
<?php endif; ?>
<label>Name</label>
<input name="name" type="text" autocomplete="name" placeholder="" required maxlength="128">
@ -52,6 +59,8 @@
</div>
<?php if(!$root): ?>
<div class="zone medium text-align-center">
<a href="/auth/signin">Already have an account?</a>
</div>
<?PHP endif; ?>

View file

@ -57,6 +57,7 @@ services:
environment:
- _APP_ENV
- _APP_LOCALE
- _APP_CONSOLE_WHITELIST_ROOT
- _APP_CONSOLE_WHITELIST_EMAILS
- _APP_CONSOLE_WHITELIST_IPS
- _APP_SYSTEM_EMAIL_NAME

View file

@ -76,6 +76,9 @@ services:
environment:
- _APP_ENV
- _APP_LOCALE
- _APP_CONSOLE_WHITELIST_ROOT
- _APP_CONSOLE_WHITELIST_EMAILS
- _APP_CONSOLE_WHITELIST_IPS
- _APP_SYSTEM_EMAIL_NAME
- _APP_SYSTEM_EMAIL_ADDRESS
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS