diff --git a/lib/index b/lib/index index f353511..31798a6 160000 --- a/lib/index +++ b/lib/index @@ -1 +1 @@ -Subproject commit f3535117cea575d6ec5c86964da69b2c018028d1 +Subproject commit 31798a6b536069bc47832545b036c0d62422400c diff --git a/misuzu.php b/misuzu.php index a339501..576df65 100644 --- a/misuzu.php +++ b/misuzu.php @@ -214,11 +214,9 @@ if($authToken->isValid()) { AuthToken::nukeCookie(); } -CSRF::setGlobalSecretKey($cfg->getValue('csrf.secret', IConfig::T_STR, 'soup')); -CSRF::setGlobalIdentity( - UserSession::hasCurrent() - ? UserSession::getCurrent()->getToken() - : ($_SERVER['REMOTE_ADDR'] ?? '::1') +CSRF::init( + $cfg->getValue('csrf.secret', IConfig::T_STR, 'soup'), + (UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : ($_SERVER['REMOTE_ADDR'] ?? '::1')) ); function mszLockdown(): void { diff --git a/src/CSRF.php b/src/CSRF.php index 95b2706..8aa2e1d 100644 --- a/src/CSRF.php +++ b/src/CSRF.php @@ -1,104 +1,28 @@ setTolerance($tolerance); - $this->setTimestamp($timestamp ?? self::timestamp()); + public static function init(string $secretKey, string $identity): void { + self::$instance = new CSRFP($secretKey, $identity); } - public static function timestamp(): int { - return time() - self::EPOCH; + public static function validate(string $token, int $tolerance = -1): bool { + return self::$instance->verifyToken($token, $tolerance); } - public static function setGlobalIdentity(string $identity): void { - self::$globalIdentity = $identity; - } - public static function setGlobalSecretKey(string $secretKey): void { - self::$globalSecretKey = $secretKey; - } - public static function validate(string $token, ?string $identity = null, ?string $secretKey = null): bool { - try { - return self::decode($token, $identity ?? self::$globalIdentity, $secretKey ?? self::$globalSecretKey)->isValid(); - } catch(Exception $ex) { - return false; - } - } - public static function token(?string $identity = null, int $tolerance = self::TOLERANCE, ?string $secretKey = null, ?int $timestamp = null): string { - return (new static($tolerance, $timestamp))->encode($identity ?? self::$globalIdentity, $secretKey ?? self::$globalSecretKey); + public static function token(): string { + return self::$instance->createToken(); } - // Should be replaced by filters eventually < - public static function validateRequest($identity = null, ?string $secretKey = null): bool { + public static function validateRequest(int $tolerance = -1): bool { $token = filter_input(INPUT_POST, '_csrf'); if(empty($token)) $token = filter_input(INPUT_GET, 'csrf'); - if(empty($token)) - return false; - return self::validate($token, $identity, $secretKey); - } - // > - public static function decode(string $token, string $identity, string $secretKey): CSRF { - $hash = substr($token, 12); - $unpacked = unpack('Vtimestamp/vtolerance', hex2bin(substr($token, 0, 12))); - - if(empty($hash) || empty($unpacked['timestamp']) || empty($unpacked['tolerance'])) - throw new InvalidArgumentException('Invalid token provided.'); - - $csrf = new static($unpacked['tolerance'], $unpacked['timestamp']); - - if(!hash_equals($csrf->getHash($identity, $secretKey), $hash)) - throw new InvalidArgumentException('Modified token.'); - - return $csrf; - } - - public function encode(string $identity, string $secretKey): string { - $token = bin2hex(pack('Vv', $this->getTimestamp(), $this->getTolerance())); - $token .= $this->getHash($identity, $secretKey); - return $token; - } - - public function getHash(string $identity, string $secretKey): string { - return hash_hmac(self::HASH_ALGO, "{$identity}|{$this->getTimestamp()}|{$this->getTolerance()}", $secretKey); - } - - public function getTimestamp(): int { - return $this->timestamp; - } - public function setTimestamp(int $timestamp): self { - if($timestamp < 0 || $timestamp > 0xFFFFFFFF) - throw new InvalidArgumentException('Timestamp must be within the constaints of an unsigned 32-bit integer.'); - $this->timestamp = $timestamp; - return $this; - } - - public function getTolerance(): int { - return $this->tolerance; - } - public function setTolerance(int $tolerance): self { - if($tolerance < 0 || $tolerance > 0xFFFF) - throw new InvalidArgumentException('Tolerance must be within the constaints of an unsigned 16-bit integer.'); - $this->tolerance = $tolerance; - return $this; - } - - public function isValid(): bool { - $currentTime = self::timestamp(); - return $currentTime >= $this->getTimestamp() && $currentTime <= $this->getTimestamp() + $this->getTolerance(); + return self::$instance->verifyToken($token, $tolerance); } }