Computer programming

Browsersync is an automation tool that can watch files for changes and inject them into a web page without reload.

Usage:

  • Install Node.js
  • Install Browsersync
    npm install -g browser-sync
  • Start Browsersync
    browser-sync start --proxy "myproject.dev" --files "css/*.css"

Browsersync will create a proxy that will wrap your vhost myproject.dev with a proxy URL.

It can also be used with gulp:

var browserSyncWatchFiles = [
'./style.css',
'./js/*.min.js',
'./*.php'
];
var browserSync = require('browser-sync').create();
var browserSyncOptions = {
proxy: "myproject.dev",
notify: false
};
gulp.task('browser-sync', function () {
browserSync.init(browserSyncWatchFiles, browserSyncOptions);
});

Technology:

The idea is to write a trait that adds encryption capabilities to the Eloquent model. The trait has an abstract getEncryptKey() method that returns the encryption key and needs to be implemented by the model class. This way the model can use a single encryption key or some logic to return different keys for different entities.
The getEncryptedFields() method returns an array of fields that need to be encrypted.
Finally the trait overrides the model's performInsert() and performUpdate() methods to implement automatic encryption. Encryption happens at the database level, so a database expression will be injected into Eloquents insert/update query. In this example Postgres pgp_sym_encrypt is used for encryption.

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
trait DatabaseEncryption
{
/**
* Initialize global scope for decryption
* @return void
*/
public static function bootDatabaseEncryption()
{
static::addGlobalScope(new DatabaseEncryptionScope());
}
/**
* Returns the encrypted fields
* @return array
*/
public static function getEncryptedFields()
{
return [];
}
/**
* Returns the encrypt key
* @return string
*/
abstract protected function getEncryptKey();
/**
* Perform insert with encryption
* @param Builder $query
* @return bool
*/
protected function performInsert(Builder $query)
{
$encryptedFields = static::getEncryptedFields();
if (count($encryptedFields) && !$this->getEncryptKey()) {
throw new \RuntimeException("No encryption key specified");
}
foreach ($encryptedFields as $encryptedField) {
$quotedText = DB::connection()->getPdo()->quote($this->attributes[$encryptedField]);
$quotedEncryptKey = DB::connection()->getPdo()->quote(static::getEncryptKey());
$this->attributes[$encryptedField] = DB::raw("pgp_sym_encrypt($quotedText, $quotedEncryptKey)");
}
return parent::performInsert($query);
}
/**
* Perform update with encryption
* @param Builder $query
* @return bool
*/
protected function performUpdate(Builder $query)
{
$encryptedFields = static::getEncryptedFields();
if (count($encryptedFields) && !$this->getEncryptKey()) {
throw new \RuntimeException("No encryption key specified");
}
foreach ($encryptedFields as $encryptedField) {
$quotedText = DB::connection()->getPdo()->quote($this->attributes[$encryptedField]);
$quotedEncryptKey = DB::connection()->getPdo()->quote(static::getEncryptKey());
$this->attributes[$encryptedField] = DB::raw("pgp_sym_encrypt($quotedText, $quotedEncryptKey)");
}
return parent::performUpdate($query);
}
}

A Eloquent query scope is used for automatic decryption. The class injects the decryption expression into all built queries.

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\DB;
class DatabaseEncryptionScope implements Scope
{
/**
* All of the extensions to be added to the builder.
*
* @var array
*/
protected $extensions = ['WithDecryptKey'];
/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
{
foreach ($model::getEncryptedFields() as $encryptedField) {
$builder->addSelect(DB::raw("$encryptedField as {$encryptedField}_encrypted"));
}
}
/**
* Extend the query builder with the needed functions.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function extend(Builder $builder)
{
foreach ($this->extensions as $extension) {
$this->{"add{$extension}"}($builder);
}
}
/**
* Add the with-decrypt-key extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addWithDecryptKey(Builder $builder)
{
$builder->macro('withDecryptKey', function (Builder $builder, $decryptKey) {
$model = $builder->getModel();
/** @var DatabaseEncryptionServiceInterface $encryptionService */
$encryptionService = $model::getEncryptionService();
foreach ($model::getEncryptedFields() as $encryptedField) {
$decryptStmt = $encryptionService->getDecryptExpression($encryptedField, $decryptKey);
$builder->addSelect(DB::raw("$decryptStmt as $encryptedField"));
}
return $builder;
});
}
}

An example model class can look like this:

namespace App;
use Anexia\EloquentEncryption\DatabaseEncryption;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable, DatabaseEncryption;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* @return array
*/
protected static function getEncryptedFields()
{
return [
'password'
];
}
/**
* @return string
*/
protected function getEncryptKey()
{
return 'dasisteinlangerencryptkey';
}
}

The user class can then be used like this:

/* Insert a new user like always. The password field will be encrypted automatically */
$user = new User([
'name' => 'name',
'email' => 'email',
'password' => 'Password'
]);
$user->save();
/* Retrieve the user */
$user = User::withDecryptKey('dasisteinlangerencryptkey')->find(1);

Technology:

Geb provides access to JavaScript variables and also allows to run JavaScript on the page. With help of that feature properties can be accessed and actions can be performed (click, etc.)

Syntax: js.exec()

In that case make sure you only remove the staged version, and add the file to your .gitignore to avoid making the same mistake a second time:
git reset filename # or git remove --cached filename
echo filename >> .gitingore # add it to .gitignore to avoid re-adding it

Taggings:

Pages

Subscribe to Computer programming