Skip to content

Commit

Permalink
new encryption system, usage in auth and cookie service providers; re…
Browse files Browse the repository at this point in the history
…moval of encryption/scramble support classes; facade docs
  • Loading branch information
donwilson committed Jan 11, 2024
1 parent fee5208 commit b0f3f06
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 296 deletions.
17 changes: 11 additions & 6 deletions src/Magnetar/Auth/AuthManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Magnetar\Model\Model;
use Magnetar\Auth\Exceptions\AuthorizationException;
use Magnetar\Http\Request;
use Magnetar\Utilities\Cryptography\Encryption;
use Magnetar\Encryption\Encryption;
use Magnetar\Utilities\Str;

/**
Expand Down Expand Up @@ -128,11 +128,20 @@ public function logout(): void {
$this->invalidateRememberCookie();
}

/**
* Get the encryption instance
* @return Encryption
*/
protected function encrypter(): Encryption {
return $this->app->make('encryption');
}

/**
* See if we remember the user by looking up the 'remember me' cookie
* @return bool
*
* @throws \Magnetar\Auth\Exceptions\AuthorizationException
* @throws \Magnetar\Encryption\Exceptions\DecryptionException
*/
public function remember(): bool {
if(null !== $this->user) {
Expand All @@ -145,11 +154,7 @@ public function remember(): bool {
}

// decode and decrypt cookie
$cookie = (new Encryption(
$this->app['config']['app.key'],
$this->app['config']['app.digest'],
$this->app['config']['app.cipher']
))->decrypt($raw_cookie);
$cookie = $this->encrypter()->decrypt($raw_cookie);

// validate cookie
if(!isset($cookie['id']) || !isset($cookie['token'])) {
Expand Down
126 changes: 37 additions & 89 deletions src/Magnetar/Auth/SessionDetails.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@

namespace Magnetar\Auth;

use Magnetar\Utilities\Cryptography\Scramble;
use Magnetar\Application;
use Magnetar\Auth\Exceptions\InvalidSessionDetailsException;
use Magnetar\Utilities\Cryptography\Encryption;

use Magnetar\Encryption\Encryption;
use Magnetar\Encryption\Exceptions\DecryptionException;
use Magnetar\Encryption\Exceptions\EncryptionException;

class SessionDetails {
/**
* SessionDetails constructor
*/
public function __construct(
protected Application $app,

/**
* The user's ID
* @var int
Expand All @@ -34,34 +38,6 @@ public function __construct(
// @TODO use session token?
}

/**
* Factory method to create a new SessionDetails instance
* @param int $id
* @param string $password
* @return static
*/
public static function make(
/**
* The user's ID
* @var int
*/
int $id,

/**
* The user's encrypted password
* @var string
*/
string $password,

/**
* The user's session token
* @var string
*/
string $token
): static {
return new static($id, $password, $token);
}

/**
* Get the user's ID
* @return int
Expand Down Expand Up @@ -107,92 +83,64 @@ public function isValid(): bool {
return true;
}

/**
* Get the encryption instance
* @return Encryption
*/
protected function encrypter(): Encryption {
return $this->app->make('encryption');
}

/**
* Encrypt this object for storage in the session
* @return string
*
* @throws \Magnetar\Auth\Exceptions\InvalidSessionDetailsException
*/
public function encryptForClient(): string {
// @TODO needs closer inspection

// confirm this object is valid
if(!$this->isValid()) {
throw new InvalidSessionDetailsException('Invalid session details');
}

// generate stored message
$message = implode('|', [
$this->getId(),
$this->getPassword(),
$this->getToken()
]);
// generate stored payload
$payload = [
'id' => $this->getId(),
'password' => $this->getPassword(),
'token' => $this->getToken()
];

// message validation
$mac = hash_hmac('sha256', $message, app()->config('app.key'));

$encrypted_message = (new Encryption(
app()->config('app.key'),
null,
app()->config('app.cipher')
))->encrypt([
'mac' => $mac,
'message' => $message,
]);

if(false === $encrypted_message) {
try {
return $this->encrypter()->encrypt($payload);
} catch(EncryptionException $e) {
throw new InvalidSessionDetailsException('Unable to encrypt session details');
}

return Scramble::encode(
$encrypted_message
);
}

/**
* Decrypt a string from the session into a SessionDetails object
* @param string $encrypted The encrypted string from the session
* @return static
*
* @throws \Magnetar\Auth\Exceptions\InvalidSessionDetailsException
*/
public static function decryptFromClient(string $encrypted): static {
// @TODO needs closer inspection

$soft_decrypted = Scramble::decode($encrypted);

if(false === $soft_decrypted) {
throw new InvalidSessionDetailsException('Unable to initially decrypt session details');
}

$decrypted = (new Encryption(
app()->config('app.key'),
null,
app()->config('app.cipher')
))->decrypt($soft_decrypted);

if(false === $decrypted) {
try {
$payload = $this->encrypter()->decrypt($encrypted);
} catch(DecryptionException $e) {
throw new InvalidSessionDetailsException('Unable to decrypt session details');
}

// validation
if(!isset($decrypted['mac']) || !isset($decrypted['message'])) {
throw new InvalidSessionDetailsException('Invalid encrypted session details');
}

// mac validation
$mac = hash_hmac('sha256', $decrypted['message'], app()->config('app.key'));

if(!hash_equals($mac, $decrypted['mac'])) {
throw new InvalidSessionDetailsException('Encrypted session details failed validation');
}

$parts = explode('|', $decrypted['message']);

if(count($parts) < 3) {
// confirm payload is valid
if(!isset($payload['id']) || !isset($payload['password']) || !isset($payload['token'])) {
throw new InvalidSessionDetailsException('Invalid session details message');
}

return new static(
(int) $parts[0],
(string) $parts[1],
(string) $parts[2]
$this->app,
(int) $payload['id'],
(string) $payload['password'],
(string) $payload['token']
);
}
}
Loading

0 comments on commit b0f3f06

Please sign in to comment.