1
0
Fork 0
mirror of synced 2024-06-01 10:29:48 +12:00

Added built-in DB encryption

This commit is contained in:
Eldad Fux 2020-05-13 01:00:00 +03:00
parent 03ec10a0b8
commit 8b878c87ff
3 changed files with 191 additions and 14 deletions

View file

@ -1212,6 +1212,15 @@ $collections = [
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Status',
'key' => 'status',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Name',
@ -1238,15 +1247,7 @@ $collections = [
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Trigger',
'key' => 'trigger',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
'filter' => ['json', 'encrypt']
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
@ -1266,6 +1267,24 @@ $collections = [
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Previous',
'key' => 'previous',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Next',
'key' => 'next',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Timeout',

View file

@ -23,6 +23,7 @@ use Appwrite\Database\Document;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\OpenSSL\OpenSSL;
use PHPMailer\PHPMailer\PHPMailer;
const APP_NAME = 'Appwrite';
@ -32,7 +33,7 @@ const APP_EMAIL_SECURITY = 'security@localhost.test'; // Default security email
const APP_USERAGENT = APP_NAME.'-Server v%s. Please report abuse at %s';
const APP_MODE_ADMIN = 'admin';
const APP_PAGING_LIMIT = 15;
const APP_CACHE_BUSTER = 126;
const APP_CACHE_BUSTER = 130;
const APP_VERSION_STABLE = '0.5.3';
const APP_STORAGE_UPLOADS = '/storage/uploads';
const APP_STORAGE_CACHE = '/storage/cache';
@ -229,6 +230,43 @@ stream_context_set_default([ // Set global user agent and http settings
],
]);
/**
* DB Filters
*/
Database::addFilter('json',
function($value) {
if(!is_array($value)) {
return $value;
}
return json_encode($value);
},
function($value) {
return json_decode($value, true);
}
);
Database::addFilter('encrypt',
function($value) use ($request) {
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$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' => '1',
]);
},
function($value) use ($request) {
$value = json_decode($value, true);
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$value['version']);
return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag']));
}
);
/*
* Auth & Project Scope
*/
@ -308,4 +346,4 @@ $register->get('smtp')
? urldecode($request->getServer('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server'))
: sprintf(Locale::getText('account.emails.team'), $project->getAttribute('name')
)
);
);

View file

@ -51,6 +51,11 @@ class Database
const SYSTEM_VAR_TYPE_URL = 'url';
const SYSTEM_VAR_TYPE_KEY = 'key';
/**
* @var array
*/
static protected $filters = [];
/**
* @var array
*/
@ -174,7 +179,7 @@ class Database
*
* @return Document
*/
public function getDocument($id, $mock = true)
public function getDocument($id, $mock = true, $decode = true)
{
if (is_null($id)) {
return new Document([]);
@ -187,6 +192,8 @@ class Database
return new Document([]);
}
$document = ($decode) ? $this->decode($document) : $document;
return $document;
}
@ -209,12 +216,18 @@ class Database
}
$validator = new Structure($this);
$document = $this->encode($document);
if (!$validator->isValid($document)) {
throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
}
$document = new Document($this->adapter->createDocument($document->getArrayCopy(), $unique));
$document = $this->decode($document);
return new Document($this->adapter->createDocument($data, $unique));
return $document;
}
/**
@ -248,13 +261,19 @@ class Database
throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
}
$new = $this->encode($new);
$validator = new Structure($this);
if (!$validator->isValid($new)) { // Make sure updated structure still apply collection rules (if any)
throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
}
return new Document($this->adapter->updateDocument($data));
$new = new Document($this->adapter->updateDocument($new->getArrayCopy()));
$new = $this->decode($new);
return $new;
}
/**
@ -380,6 +399,107 @@ class Database
return $this->mocks;
}
/**
* Add Attribute Filter
*
* @param string $name
* @param callable $encode
* @param callable $decode
*
* return $this
*/
static public function addFilter(string $name, callable $encode, callable $decode)
{
self::$filters[$name] = [
'encode' => $encode,
'decode' => $decode,
];
}
public function encode(Document $document):Document
{
$collection = $this->getDocument($document->getCollection(), true , false);
$rules = $collection->getAttribute('rules', []);
foreach ($rules as $key => $rule) {
$key = $rule->getAttribute('key', null);
$filters = $rule->getAttribute('filter', null);
$value = $document->getAttribute($key, null);
if(($value !== null) && is_array($filters)) {
foreach ($filters as $filter) {
$value = $this->encodeAttribute($filter, $value);
$document->setAttribute($key, $value);
}
}
}
return $document;
}
public function decode(Document $document):Document
{
$collection = $this->getDocument($document->getCollection(), true , false);
$rules = $collection->getAttribute('rules', []);
foreach ($rules as $key => $rule) {
$key = $rule->getAttribute('key', null);
$filters = $rule->getAttribute('filter', null);
$value = $document->getAttribute($key, null);
if(($value !== null) && is_array($filters)) {
foreach (array_reverse($filters) as $filter) {
$value = $this->decodeAttribute($filter, $value);
$document->setAttribute($key, $value);
}
}
}
return $document;
}
/**
* Encode Attribute
*
* @param string $name
* @param mixed $value
*/
static protected function encodeAttribute(string $name, $value)
{
if(!isset(self::$filters[$name])) {
throw new Exception('Filter not found');
}
try {
$value = self::$filters[$name]['encode']($value);
} catch (\Throwable $th) {
$value = null;
}
return $value;
}
/**
* Decode Attribute
*
* @param string $name
* @param mixed $value
*/
static protected function decodeAttribute(string $name, $value)
{
if(!isset(self::$filters[$name])) {
throw new Exception('Filter not found');
}
try {
$value = self::$filters[$name]['decode']($value);
} catch (\Throwable $th) {
$value = null;
}
return $value;
}
/**
* Get Last Modified.
*