Skip to content

Commit

Permalink
Add option to encrypt shared secret and recovery codes
Browse files Browse the repository at this point in the history
  • Loading branch information
srichter committed Apr 25, 2021
1 parent 36ae690 commit eeaecdf
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 2 deletions.
13 changes: 13 additions & 0 deletions config/laraguard.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@

'secret_length' => 20,

/*
|--------------------------------------------------------------------------
| Encryption
|--------------------------------------------------------------------------
|
| Control whether the shared secret and recovery codes are encrypted when
| stored in the database.
| Note: If this is set to true, the secret_length cannot be larger than 25.
|
*/

'encrypted' => false,

/*
|--------------------------------------------------------------------------
| TOTP config
Expand Down
2 changes: 1 addition & 1 deletion src/Eloquent/HandlesCodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ protected function timestampToBinary(int $timestamp)
*/
protected function getBinarySecret()
{
return Base32::decodeUpper($this->attributes['shared_secret']);
return Base32::decodeUpper($this->shared_secret);
}

/**
Expand Down
33 changes: 33 additions & 0 deletions src/Eloquent/HandlesRecoveryCodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Support\Str;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Crypt;

trait HandlesRecoveryCodes
{
Expand Down Expand Up @@ -69,4 +70,36 @@ public static function generateRecoveryCodes(int $amount, int $length)
];
});
}

/**
* Encrypts the Recovery Codes.
*
* @param mixed $codes
* @return \Illuminate\Support\Collection|null
*/
public static function encryptRecoveryCodes($codes)
{
return optional($codes)->map(function ($item) {
return [
'code' => Crypt::encryptString($item['code']),
'used_at' => $item['used_at'],
];
});
}

/**
* Decrypts the Recovery Codes.
*
* @param mixed $codes
* @return \Illuminate\Support\Collection|null
*/
public static function decryptRecoveryCodes($codes)
{
return optional($codes)->map(function ($item) {
return [
'code' => Crypt::decryptString($item['code']),
'used_at' => $item['used_at'],
];
});
}
}
55 changes: 54 additions & 1 deletion src/Eloquent/TwoFactorAuthentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ class TwoFactorAuthentication extends Model implements TwoFactorTotp
'recovery_codes_generated_at',
];

/**
* Create a new Eloquent model instance.
*
* @param array $attributes
* @return void
*/
public function __construct(array $attributes = [])
{
if (config('laraguard.encrypted')) {
$this->mergeCasts([
'shared_secret' => 'encrypted',
]);
}

parent::__construct($attributes);
}

/**
* The model that uses Two Factor Authentication.
*
Expand All @@ -82,6 +99,42 @@ protected function setAlgorithmAttribute($value)
$this->attributes['algorithm'] = strtolower($value);
}

/**
* Gets the Recovery Codes attribute, optionally from its encrypted form.
*
* @param mixed $value
* @return \Illuminate\Support\Collection|null
*/
protected function getRecoveryCodesAttribute($value)
{
$value = $this->castAttribute('recovery_codes', $value);

if (config('laraguard.encrypted')) {
$value = static::decryptRecoveryCodes($value);
}

return $value;
}

/**
* Sets the Recovery Codes attribute, optionally to its encrypted form.
*
* @param mixed $value
* @return $this
*/
protected function setRecoveryCodesAttribute($value)
{
if (config('laraguard.encrypted')) {
$value = static::encryptRecoveryCodes($value);
}

$value = $this->castAttributeAsJson('recovery_codes', $value);

$this->attributes['recovery_codes'] = $value;

return $this;
}

/**
* Returns if the Two Factor Authentication has been enabled.
*
Expand Down Expand Up @@ -116,7 +169,7 @@ public function flushAuth()

$this->attributes = array_merge($this->attributes, config('laraguard.totp'));

$this->attributes['shared_secret'] = static::generateRandomSecret();
$this->setAttribute('shared_secret', static::generateRandomSecret());

return $this;
}
Expand Down

0 comments on commit eeaecdf

Please sign in to comment.