PHP Classes

File: src/Purpose.php

Recommend this page to a friend!
  Classes of Scott Arciszewski   PHP PASeTo   src/Purpose.php   Download  
File: src/Purpose.php
Role: Class source
Content type: text/plain
Description: Class source
Class: PHP PASeTo
Encrypt and decrypt data with PaSeTO protocol
Author: By
Last change:
Date: 4 years ago
Size: 6,690 bytes
 

Contents

Class file image Download
<?php
declare(strict_types=1);
namespace
ParagonIE\Paseto;

use
ParagonIE\Paseto\Keys\{
   
AsymmetricSecretKey,
   
AsymmetricPublicKey,
   
SymmetricKey
};
use
ParagonIE\Paseto\Keys\Version1\{
   
AsymmetricSecretKey as V1AsymmetricSecretKey,
   
AsymmetricPublicKey as V1AsymmetricPublicKey,
   
SymmetricKey as V1SymmetricKey
};
use
ParagonIE\Paseto\Keys\Version2\{
   
AsymmetricSecretKey as V2AsymmetricSecretKey,
   
AsymmetricPublicKey as V2AsymmetricPublicKey,
   
SymmetricKey as V2SymmetricKey
};
use
ParagonIE\Paseto\Exception\InvalidPurposeException;

/**
 * Class Purpose
 * @package ParagonIE\Paseto
 */
final class Purpose
{
   
/**
     * A whitelist of allowed values/modes. This simulates an enum.
     * @const array<int, string>
     */
   
const WHITELIST = [
       
'local',
       
'public',
    ];

   
/**
     * When sending, which type of key is expected for each mode.
     * @const array<string, string>
     */
   
const EXPECTED_SENDING_KEYS = [
       
'local' => SymmetricKey::class,
       
'public' => AsymmetricSecretKey::class,
    ];

   
/**
     * Maps the fully-qualified class names for various SendingKey
     * objects to the expected purpose string.
     * @const array<string, string>
     */
   
const SENDING_KEY_MAP = [
       
SymmetricKey::class => 'local',
       
V1SymmetricKey::class => 'local',
       
V2SymmetricKey::class => 'local',
       
AsymmetricSecretKey::class => 'public',
       
V1AsymmetricSecretKey::class => 'public',
       
V2AsymmetricSecretKey::class => 'public'
   
];

   
/**
     * When receiving, which type of key is expected for each mode.
     * @const array<string, string>
     */
   
const EXPECTED_RECEIVING_KEYS = [
       
'local' => SymmetricKey::class,
       
'public' => AsymmetricPublicKey::class,
    ];

   
/**
     * Maps the fully-qualified class names for various ReceivingKey
     * objects to the expected purpose string.
     * @const array<string, string>
     */
   
const RECEIVING_KEY_MAP = [
       
SymmetricKey::class => 'local',
       
V1SymmetricKey::class => 'local',
       
V2SymmetricKey::class => 'local',
       
AsymmetricPublicKey::class => 'public',
       
V1AsymmetricPublicKey::class => 'public',
       
V2AsymmetricPublicKey::class => 'public'
   
];

   
/**
     * Inverse of EXPECTED_SENDING_KEYS, evaluated and statically cached at
     * runtime.
     * @var array<string, string>
     */
   
private static $sendingKeyToPurpose;

   
/**
     * Inverse of EXPECTED_RECEIVING_KEYS, evaluated and statically cached at
     * runtime.
     * @var array<string, string>
     */
   
private static $receivingKeyToPurpose;

   
/**
     * @var string
     */
   
private $purpose;

   
/**
     * Allowed values in self::WHITELIST
     *
     * @param string $rawString
     * @throws InvalidPurposeException
     */
   
public function __construct(string $rawString)
    {
        if (!
self::isValid($rawString)) {
            throw new
InvalidPurposeException('Unknown purpose: ' . $rawString);
        }

       
$this->purpose = $rawString;
    }

   
/**
     * Create a local purpose.
     *
     * @return self
     * @throws InvalidPurposeException
     */
   
public static function local(): self
   
{
        return new
self('local');
    }

   
/**
     * Create a public purpose.
     *
     * @return self
     * @throws InvalidPurposeException
     */
   
public static function public(): self
   
{
        return new
self('public');
    }

   
/**
     * Given a SendingKey, retrieve the corresponding Purpose.
     *
     * @param SendingKey $key
     *
     * @return self
     * @throws InvalidPurposeException
     */
   
public static function fromSendingKey(SendingKey $key): self
   
{
        if (empty(
self::$sendingKeyToPurpose)) {
           
/** @var array<string, string> */
           
self::$sendingKeyToPurpose = self::SENDING_KEY_MAP;
        }

        return new
self(self::$sendingKeyToPurpose[\get_class($key)]);
    }

   
/**
     * Given a ReceivingKey, retrieve the corresponding Purpose.
     *
     * @param ReceivingKey $key
     *
     * @return self
     * @throws InvalidPurposeException
     */
   
public static function fromReceivingKey(ReceivingKey $key): self
   
{
        if (empty(
self::$receivingKeyToPurpose)) {
           
/** @var array<string, string> */
           
self::$sendingKeyToPurpose = self::RECEIVING_KEY_MAP;
        }

        return new
self(self::$receivingKeyToPurpose[\get_class($key)]);
    }

   
/**
     * Compare the instance with $purpose in constant time.
     *
     * @param self $purpose
     * @return bool
     */
   
public function equals(self $purpose): bool
   
{
        return \
hash_equals($purpose->purpose, $this->purpose);
    }

   
/**
     * Determine whether new Purpose($rawString) will succeed prior to calling
     * it.
     *
     * @param string $rawString
     * @return bool
     */
   
public static function isValid(string $rawString): bool
   
{
        return \
in_array($rawString, self::WHITELIST, true);
    }

   
/**
     * Does the given $key correspond to the expected SendingKey for the
     * instance's mode?
     *
     * @param SendingKey $key
     * @return bool
     */
   
public function isSendingKeyValid(SendingKey $key): bool
   
{
       
$expectedKeyType = $this->expectedSendingKeyType();
        return
$key instanceof $expectedKeyType;
    }

   
/**
     * Does the given $key correspond to the expected ReceivingKey for the
     * instance's mode?
     *
     * @param ReceivingKey $key
     * @return bool
     */
   
public function isReceivingKeyValid(ReceivingKey $key): bool
   
{
       
$expectedKeyType = $this->expectedReceivingKeyType();
        return
$key instanceof $expectedKeyType;
    }

   
/**
     * Retrieve the class name as a string which corresponds to the expected
     * SendingKey for the instance's mode.
     *
     * @return string
     */
   
public function expectedSendingKeyType(): string
   
{
       
/** @var string */
       
$keyType = self::EXPECTED_SENDING_KEYS[$this->rawString()];

        return
$keyType;
    }

   
/**
     * Retrieve the class name as a string which corresponds to the expected
     * ReceivingKey for the instance's mode.
     *
     * @return string
     */
   
public function expectedReceivingKeyType(): string
   
{
       
/** @var string */
       
$keyType = self::EXPECTED_RECEIVING_KEYS[$this->rawString()];

        return
$keyType;
    }

   
/**
     * Retrieve the underlying raw string value for the instance's mode.
     *
     * @return string
     */
   
public function rawString(): string
   
{
        return
$this->purpose;
    }
}