mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
51
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ead2a7f36 | ||
|
|
4cbef8614e | ||
|
|
d7a94cc4c6 | ||
|
|
3b62798667 | ||
|
|
adc8be01d0 | ||
|
|
951a553344 | ||
|
|
6c738b0dcc | ||
|
|
6248225949 | ||
|
|
fab93f755a | ||
|
|
7bd4e08b68 | ||
|
|
77b38e3a5e | ||
|
|
7de544957d | ||
|
|
f403b8235a | ||
|
|
58d00055d9 | ||
|
|
bcc0e0df18 | ||
|
|
43332fbc05 | ||
|
|
8f22a72e41 | ||
|
|
f2482ab88d | ||
|
|
c0a616c009 | ||
|
|
8718437304 | ||
|
|
44f81d9453 | ||
|
|
6000177291 | ||
|
|
c90986068d | ||
|
|
acad5815b5 | ||
|
|
afa02062a3 | ||
|
|
c4a722620f | ||
|
|
3d43a9759a | ||
|
|
ea3544579b | ||
|
|
aa92551369 | ||
|
|
87f8188665 | ||
|
|
967c751926 | ||
|
|
369a42c3d0 | ||
|
|
6286bcaf46 | ||
|
|
77e95466e5 | ||
|
|
60ab3a801b | ||
|
|
feee2bf473 | ||
|
|
057d56621f | ||
|
|
33100df180 | ||
|
|
2c00148431 | ||
|
|
d4897b2eea | ||
|
|
e9b553fa85 | ||
|
|
c923e2e41b | ||
|
|
89d4c82d58 | ||
|
|
c09bf14d29 | ||
|
|
7ca0696aee | ||
|
|
c4e3de8bb3 | ||
|
|
5750f0927b | ||
|
|
7489ec40de | ||
|
|
5f052645ec | ||
|
|
3d7f48ea0c | ||
|
|
8898cfa58e |
@@ -633,6 +633,28 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('databaseSecrets'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => false,
|
||||
'filters' => ['json', 'encrypt'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('jwtSecrets'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => false,
|
||||
'filters' => ['encrypt'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('services'),
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -3301,15 +3323,15 @@ $collections = [
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('openSSLVersion'),
|
||||
'$id' => ID::custom('fileSecret'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 64,
|
||||
'size' => 512,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
'filters' => ['encrypt'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('openSSLCipher'),
|
||||
|
||||
@@ -1239,9 +1239,9 @@ App::post('/v1/account/jwt')
|
||||
->label('abuse-key', 'url:{url},userId:{userId}')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->action(function (Response $response, Document $user, Database $dbForProject) {
|
||||
|
||||
->action(function (Response $response, Document $user, Document $project, Database $dbForProject) {
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$current = new Document();
|
||||
@@ -1256,7 +1256,7 @@ App::post('/v1/account/jwt')
|
||||
throw new Exception(Exception::USER_SESSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
$jwt = new JWT($project->getAttribute('jwtSecrets'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
|
||||
@@ -1034,7 +1034,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
}
|
||||
|
||||
if (!$current->isEmpty()) {
|
||||
$jwtObj = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
$jwtObj = new JWT($project->getAttribute('jwtSecrets'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
$jwt = $jwtObj->encode([
|
||||
'userId' => $user->getId(),
|
||||
'sessionId' => $current->getId(),
|
||||
|
||||
@@ -28,6 +28,7 @@ use Utopia\Database\Validator\UID;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Registry\Registry;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
@@ -119,6 +120,8 @@ App::post('/v1/projects')
|
||||
'keys' => null,
|
||||
'domains' => null,
|
||||
'auths' => $auths,
|
||||
'databaseSecrets' => [\uniqid() => OpenSSL::secretString()],
|
||||
'jwtSecrets' => OpenSSL::secretString(),
|
||||
'search' => implode(' ', [$projectId, $name]),
|
||||
]));
|
||||
/** @var array $collections */
|
||||
@@ -864,6 +867,7 @@ App::post('/v1/projects/:projectId/keys')
|
||||
'name' => $name,
|
||||
'scopes' => $scopes,
|
||||
'expire' => $expire,
|
||||
'secret' => Auth::tokenGenerator(),
|
||||
'sdks' => [],
|
||||
'accessedAt' => null,
|
||||
'secret' => \bin2hex(\random_bytes(128)),
|
||||
|
||||
@@ -528,9 +528,16 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
if (empty($data)) {
|
||||
$data = $deviceFiles->read($path);
|
||||
}
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
|
||||
|
||||
$fileSecret = OpenSSL::secretString();
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
|
||||
$tag = null;
|
||||
|
||||
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $fileSecret, 0, $iv, $tag);
|
||||
|
||||
$openSSLCipher = OpenSSL::CIPHER_AES_128_GCM;
|
||||
$openSSLTag = \bin2hex($tag ?? '');
|
||||
$openSSLIV = \bin2hex($iv);
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
@@ -542,13 +549,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$sizeActual = $deviceFiles->getFileSize($path);
|
||||
$fileHash = $deviceFiles->getFileHash($path);
|
||||
|
||||
if ($bucket->getAttribute('encryption', true) && $fileSize <= APP_STORAGE_READ_BUFFER) {
|
||||
$openSSLVersion = '1';
|
||||
$openSSLCipher = OpenSSL::CIPHER_AES_128_GCM;
|
||||
$openSSLTag = \bin2hex($tag);
|
||||
$openSSLIV = \bin2hex($iv);
|
||||
}
|
||||
|
||||
try {
|
||||
if ($file->isEmpty()) {
|
||||
$doc = new Document([
|
||||
@@ -565,12 +565,12 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
'comment' => '',
|
||||
'chunksTotal' => $chunks,
|
||||
'chunksUploaded' => $chunksUploaded,
|
||||
'openSSLVersion' => $openSSLVersion,
|
||||
'openSSLCipher' => $openSSLCipher,
|
||||
'openSSLTag' => $openSSLTag,
|
||||
'openSSLIV' => $openSSLIV,
|
||||
'openSSLCipher' => $openSSLCipher ?? null,
|
||||
'openSSLTag' => $openSSLTag ?? null,
|
||||
'openSSLIV' => $openSSLIV ?? null,
|
||||
'search' => implode(' ', [$fileId, $fileName]),
|
||||
'metadata' => $metadata,
|
||||
'fileSecret' => $fileSecret ?? null,
|
||||
]);
|
||||
|
||||
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
|
||||
@@ -581,12 +581,12 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
->setAttribute('mimeType', $mimeType)
|
||||
->setAttribute('sizeActual', $sizeActual)
|
||||
->setAttribute('algorithm', $algorithm)
|
||||
->setAttribute('openSSLVersion', $openSSLVersion)
|
||||
->setAttribute('openSSLCipher', $openSSLCipher)
|
||||
->setAttribute('openSSLTag', $openSSLTag)
|
||||
->setAttribute('openSSLIV', $openSSLIV)
|
||||
->setAttribute('openSSLCipher', $openSSLCipher ?? null)
|
||||
->setAttribute('openSSLTag', $openSSLTag ?? null)
|
||||
->setAttribute('openSSLIV', $openSSLIV ?? null)
|
||||
->setAttribute('metadata', $metadata)
|
||||
->setAttribute('chunksUploaded', $chunksUploaded);
|
||||
->setAttribute('chunksUploaded', $chunksUploaded)
|
||||
->setAttribute('fileSecret', $fileSecret ?? null);
|
||||
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
}
|
||||
@@ -616,6 +616,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
'chunksUploaded' => $chunksUploaded,
|
||||
'search' => implode(' ', [$fileId, $fileName]),
|
||||
'metadata' => $metadata,
|
||||
'fileSecret' => $fileSecret ?? null,
|
||||
]);
|
||||
|
||||
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
|
||||
@@ -890,7 +891,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
$file->getAttribute('fileSecret'),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
@@ -1033,7 +1034,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
$file->getAttribute('fileSecret'),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
@@ -1183,7 +1184,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
$file->getAttribute('fileSecret'),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
|
||||
+63
-8
@@ -425,7 +425,7 @@ Database::addFilter(
|
||||
'method' => OpenSSL::CIPHER_AES_128_GCM,
|
||||
'iv' => \bin2hex($iv),
|
||||
'tag' => \bin2hex($tag ?? ''),
|
||||
'version' => '1',
|
||||
'version' => 'v1',
|
||||
]);
|
||||
},
|
||||
function (mixed $value) {
|
||||
@@ -853,7 +853,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
|
||||
$authJWT = $request->getHeader('x-appwrite-jwt', '');
|
||||
|
||||
if (!empty($authJWT) && !$project->isEmpty()) { // JWT authentication
|
||||
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
$jwt = new JWT($project->getAttribute('jwtSecrets'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
|
||||
try {
|
||||
$payload = $jwt->decode($authJWT);
|
||||
@@ -917,6 +917,8 @@ App::setResource('console', function () {
|
||||
'legalCity' => '',
|
||||
'legalAddress' => '',
|
||||
'legalTaxId' => '',
|
||||
'databaseSecrets' => ['v1' => App::getEnv('_APP_OPENSSL_KEY_V1')],
|
||||
'jwtSecrets' => App::getEnv('_APP_OPENSSL_KEY_V1'),
|
||||
'auths' => [
|
||||
'limit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
|
||||
],
|
||||
@@ -925,25 +927,78 @@ App::setResource('console', function () {
|
||||
]);
|
||||
}, []);
|
||||
|
||||
App::setResource('dbForProject', function ($db, $cache, Document $project) {
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
function encode(mixed $value, array $secrets): string
|
||||
{
|
||||
$version = array_key_last($secrets);
|
||||
$key = $secrets[$version];
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
$tag = null;
|
||||
return json_encode([
|
||||
'data' => OpenSSL::encrypt($value, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
|
||||
'method' => OpenSSL::CIPHER_AES_128_GCM,
|
||||
'iv' => \bin2hex($iv),
|
||||
'tag' => \bin2hex($tag ?? ''),
|
||||
'version' => $version,
|
||||
]);
|
||||
}
|
||||
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
function decode(?string $value, array $secrets): mixed
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
$value = json_decode($value, true);
|
||||
$version = $value['version'];
|
||||
$key = $secrets[$version];
|
||||
|
||||
return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag']));
|
||||
}
|
||||
|
||||
App::setResource('dbForProject', function ($db, $cache, $project) {
|
||||
$filters = [];
|
||||
if (!$project->isEmpty()) {
|
||||
$secrets = $project->getAttribute('databaseSecrets');
|
||||
$filters['encrypt'] = [
|
||||
'encode' => function ($value) use ($secrets) {
|
||||
return encode($value, $secrets);
|
||||
},
|
||||
'decode' => function ($value) use ($secrets) {
|
||||
return decode($value, $secrets);
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
$database = new Database(new MariaDB($db), $cache, $filters);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace("_{$project->getInternalId()}");
|
||||
|
||||
return $database;
|
||||
}, ['db', 'cache', 'project']);
|
||||
|
||||
App::setResource('dbForConsole', function ($db, $cache) {
|
||||
App::setResource('dbForConsole', function ($db, $cache, $console) {
|
||||
$filters = [];
|
||||
if (!$console->isEmpty()) {
|
||||
$secrets = $console->getAttribute('databaseSecrets');
|
||||
|
||||
$filters['encrypt'] = [
|
||||
'encode' => function ($value) use ($secrets) {
|
||||
return encode($value, $secrets);
|
||||
},
|
||||
'decode' => function ($value) use ($secrets) {
|
||||
return decode($value, $secrets);
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
$database = new Database(new MariaDB($db), $cache, $filters);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace('_console');
|
||||
|
||||
return $database;
|
||||
}, ['db', 'cache']);
|
||||
}, ['db', 'cache', 'console']);
|
||||
|
||||
|
||||
App::setResource('deviceLocal', function () {
|
||||
|
||||
+53
-7
@@ -3,6 +3,7 @@
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
use Swoole\Http\Response as SwooleResponse;
|
||||
@@ -95,7 +96,41 @@ $logError = function (Throwable $error, string $action) use ($register) {
|
||||
|
||||
$server->error($logError);
|
||||
|
||||
function getDatabase(Registry &$register, string $namespace)
|
||||
function getFilters(Document $project): array
|
||||
{
|
||||
if (!$project->isEmpty()) {
|
||||
$secrets = $project->getAttribute('databaseSecrets');
|
||||
|
||||
$filters['encrypt'] = [
|
||||
'encode' => function ($value) use ($secrets) {
|
||||
$version = array_key_last($secrets);
|
||||
$key = $secrets[$version];
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
$tag = null;
|
||||
return json_encode([
|
||||
'data' => OpenSSL::encrypt($value, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
|
||||
'method' => OpenSSL::CIPHER_AES_128_GCM,
|
||||
'iv' => \bin2hex($iv),
|
||||
'tag' => \bin2hex($tag ?? ''),
|
||||
'version' => $version,
|
||||
]);
|
||||
},
|
||||
'decode' => function ($value) use ($secrets) {
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
$value = json_decode($value, true);
|
||||
$version = $value['version'];
|
||||
$key = $secrets[$version];
|
||||
|
||||
return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag']));
|
||||
}
|
||||
];
|
||||
}
|
||||
return $filters;
|
||||
}
|
||||
|
||||
function getDatabase(Registry &$register, string $namespace, ?Document $project = null)
|
||||
{
|
||||
$attempts = 0;
|
||||
|
||||
@@ -115,6 +150,13 @@ function getDatabase(Registry &$register, string $namespace)
|
||||
throw new Exception('Collection not ready');
|
||||
}
|
||||
|
||||
if (!is_null($project)) {
|
||||
$filters = getFilters($project);
|
||||
$database = new Database(new MariaDB($db), $cache, $filters);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace($namespace);
|
||||
}
|
||||
|
||||
break; // leave loop if successful
|
||||
} catch (\Throwable $e) {
|
||||
Console::warning("Database not ready. Retrying connection ({$attempts})...");
|
||||
@@ -307,7 +349,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId]));
|
||||
[$consoleDatabase, $returnConsoleDatabase] = getDatabase($register, '_console');
|
||||
$project = Authorization::skip(fn() => $consoleDatabase->getDocument('projects', $projectId));
|
||||
[$database, $returnDatabase] = getDatabase($register, "_{$project->getInternalId()}");
|
||||
[$database, $returnDatabase] = getDatabase($register, "_{$project->getInternalId()}", $project);
|
||||
|
||||
$user = $database->getDocument('users', $userId);
|
||||
|
||||
@@ -491,13 +533,17 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
$cache = new Cache(new RedisCache($redis));
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace("_console");
|
||||
$projectId = $realtime->connections[$connection]['projectId'];
|
||||
|
||||
if ($projectId !== 'console') {
|
||||
$project = Authorization::skip(fn() => $database->getDocument('projects', $projectId));
|
||||
$database->setNamespace("_{$project->getInternalId()}");
|
||||
$projectId = $realtime->connections[$connection]['projectId'];
|
||||
$database->setNamespace("_console");
|
||||
$project = Authorization::skip(fn() => $database->getDocument('projects', $projectId));
|
||||
|
||||
if ($projectId != 'console') {
|
||||
$filters = getFilters($project);
|
||||
$database = new Database(new MariaDB($db), $cache, $filters);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
}
|
||||
$database->setNamespace("_{$project->getInternalId()}");
|
||||
|
||||
/*
|
||||
* Abuse Check
|
||||
|
||||
@@ -59,4 +59,20 @@ class OpenSSL
|
||||
{
|
||||
return \openssl_random_pseudo_bytes($length, $crypto_strong);
|
||||
}
|
||||
|
||||
/**
|
||||
* Secret String
|
||||
*
|
||||
* Generate random encryption secret
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function secretString(int $length = 128): string
|
||||
{
|
||||
return \bin2hex(self::randomPseudoBytes($length));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Appwrite\Resque;
|
||||
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
@@ -223,12 +224,46 @@ abstract class Worker
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
$database = new Database(new MariaDB($register->get('db')), $cache);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace($namespace); // Main DB
|
||||
|
||||
if (!empty($projectId) && !$database->getDocument('projects', $projectId)->isEmpty()) {
|
||||
throw new \Exception("Project does not exist: {$projectId}");
|
||||
if (!empty($projectId)) {
|
||||
$database->setNamespace("_console");
|
||||
$project = $database->getDocument('projects', $projectId);
|
||||
if (!$project->isEmpty()) {
|
||||
$secrets = $project->getAttribute('databaseSecrets');
|
||||
|
||||
$filters['encrypt'] = [
|
||||
'encode' => function ($value) use ($secrets) {
|
||||
$version = array_key_last($secrets);
|
||||
$key = $secrets[$version];
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
$tag = null;
|
||||
return json_encode([
|
||||
'data' => OpenSSL::encrypt($value, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
|
||||
'method' => OpenSSL::CIPHER_AES_128_GCM,
|
||||
'iv' => \bin2hex($iv),
|
||||
'tag' => \bin2hex($tag ?? ''),
|
||||
'version' => $version,
|
||||
]);
|
||||
},
|
||||
'decode' => function ($value) use ($secrets) {
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = json_decode($value, true);
|
||||
$version = $value['version'];
|
||||
$key = $secrets[$version];
|
||||
|
||||
return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag']));
|
||||
}
|
||||
];
|
||||
|
||||
$database = new Database(new MariaDB($register->get('db')), $cache, $filters);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
}
|
||||
}
|
||||
|
||||
$database->setNamespace($namespace); // Main DB
|
||||
if ($type === self::DATABASE_CONSOLE && !$database->exists($database->getDefaultDatabase(), '_metadata')) {
|
||||
throw new \Exception('Console project not ready');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user