Allowance check
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class PhysicalAttendanceGateCode
|
||||
{
|
||||
/** @var string */
|
||||
protected $secret;
|
||||
|
||||
/** @var int */
|
||||
protected $period;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->secret = (string) config('physical_attendance_gate.secret');
|
||||
$this->period = max(30, (int) config('physical_attendance_gate.period_seconds', 60));
|
||||
}
|
||||
|
||||
public function isConfigured()
|
||||
{
|
||||
return $this->secret !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Current code and countdown for the counter display.
|
||||
*
|
||||
* @param int $electionId
|
||||
* @return array{code:string,seconds_remaining:int,period_seconds:int}
|
||||
*/
|
||||
public function currentPayload($electionId)
|
||||
{
|
||||
$slot = $this->currentSlot();
|
||||
$code = $this->codeForSlot((int) $electionId, $slot);
|
||||
$expiresAt = ($slot + 1) * $this->period;
|
||||
$secondsRemaining = max(0, $expiresAt - time());
|
||||
|
||||
return [
|
||||
'code' => $code,
|
||||
'seconds_remaining' => $secondsRemaining,
|
||||
'period_seconds' => $this->period,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept current, previous, or next slot to tolerate minor clock skew.
|
||||
*
|
||||
* @param int $electionId
|
||||
* @param string $input
|
||||
* @return bool
|
||||
*/
|
||||
public function validates($electionId, $input)
|
||||
{
|
||||
if (!$this->isConfigured()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$normalized = strtoupper(preg_replace('/\s+/', '', (string) $input));
|
||||
|
||||
if (strlen($normalized) < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$slot = $this->currentSlot();
|
||||
|
||||
foreach ([$slot - 1, $slot, $slot + 1] as $s) {
|
||||
if ($s < 0) {
|
||||
continue;
|
||||
}
|
||||
if (hash_equals($this->codeForSlot((int) $electionId, $s), $normalized)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function currentSlot()
|
||||
{
|
||||
return intdiv(time(), $this->period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deterministic code for one election and time slot.
|
||||
*
|
||||
* @param int $electionId
|
||||
* @param int $slot
|
||||
* @return string
|
||||
*/
|
||||
protected function codeForSlot($electionId, $slot)
|
||||
{
|
||||
$material = (string) $electionId.'|'.(string) $slot;
|
||||
$hex = hash_hmac('sha256', $material, $this->secret);
|
||||
|
||||
return strtoupper(substr($hex, 0, 8));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user