53 lines
1.7 KiB
PHP
53 lines
1.7 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Services\Visio;
|
||
|
|
|
||
|
|
use App\Models\Seance;
|
||
|
|
use RuntimeException;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Jeton JWT (HS256) qui ouvre une salle Jitsi : Prosody le vérifie avec le
|
||
|
|
* même secret. Le nom vient du jeton et ne se modifie pas ; seul le prof a
|
||
|
|
* moderator = true (module natif token_affiliation de Prosody).
|
||
|
|
*/
|
||
|
|
class JetonVisio
|
||
|
|
{
|
||
|
|
public function pour(Seance $seance, string $identifiant, string $nom, bool $moderateur): string
|
||
|
|
{
|
||
|
|
$secret = config('visio.jwt.secret');
|
||
|
|
|
||
|
|
if (! is_string($secret) || strlen($secret) < 32 || $seance->visio_salle === null) {
|
||
|
|
throw new RuntimeException('Visio non configurée ou salle non ouverte.');
|
||
|
|
}
|
||
|
|
|
||
|
|
$maintenant = time();
|
||
|
|
$charge = [
|
||
|
|
'iss' => config('visio.jwt.app_id'),
|
||
|
|
'aud' => config('visio.jwt.audience'),
|
||
|
|
'sub' => '*',
|
||
|
|
'room' => $seance->visio_salle,
|
||
|
|
'iat' => $maintenant,
|
||
|
|
'nbf' => $maintenant - 10,
|
||
|
|
'exp' => $maintenant + 60 * (int) config('visio.jwt.duree_minutes'),
|
||
|
|
'context' => [
|
||
|
|
'user' => [
|
||
|
|
'id' => $identifiant,
|
||
|
|
'name' => $nom,
|
||
|
|
'moderator' => $moderateur,
|
||
|
|
],
|
||
|
|
],
|
||
|
|
];
|
||
|
|
|
||
|
|
$entete = $this->base64Url(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
|
||
|
|
$corps = $this->base64Url(json_encode($charge, JSON_UNESCAPED_UNICODE));
|
||
|
|
$signature = $this->base64Url(hash_hmac('sha256', "{$entete}.{$corps}", $secret, true));
|
||
|
|
|
||
|
|
return "{$entete}.{$corps}.{$signature}";
|
||
|
|
}
|
||
|
|
|
||
|
|
private function base64Url(string $donnees): string
|
||
|
|
{
|
||
|
|
return rtrim(strtr(base64_encode($donnees), '+/', '-_'), '=');
|
||
|
|
}
|
||
|
|
}
|