44
55use CodingLibs \MFA \Channels \EmailChannel ;
66use CodingLibs \MFA \Channels \SmsChannel ;
7+ use CodingLibs \MFA \ChannelRegistry ;
8+ use CodingLibs \MFA \Contracts \MfaChannel ;
9+ use CodingLibs \MFA \Support \QrCodeGenerator ;
710use CodingLibs \MFA \Models \MfaChallenge ;
811use CodingLibs \MFA \Models \MfaMethod ;
912use CodingLibs \MFA \Totp \GoogleTotp ;
1518class MFA
1619{
1720 protected array $ config ;
21+ protected ChannelRegistry $ registry ;
1822
1923 public function __construct (array $ config )
2024 {
2125 $ this ->config = $ config ;
26+ $ this ->registry = new ChannelRegistry ();
27+ $ this ->registerDefaultChannels ();
28+ }
29+
30+ protected function registerDefaultChannels (): void
31+ {
32+ $ this ->registry ->register (new EmailChannel ($ this ->config ['email ' ] ?? []));
33+ $ this ->registry ->register (new SmsChannel ($ this ->config ['sms ' ] ?? []));
2234 }
2335
2436 public function setupTotp (Authenticatable $ user , ?string $ issuer = null , ?string $ label = null ): array
@@ -58,7 +70,8 @@ public function verifyTotp(Authenticatable $user, string $code): bool
5870 public function issueChallenge (Authenticatable $ user , string $ method ): ?MfaChallenge
5971 {
6072 $ method = strtolower ($ method );
61- if (! in_array ($ method , ['email ' , 'sms ' ], true )) {
73+ $ channel = $ this ->registry ->get ($ method );
74+ if (! $ channel ) {
6275 return null ;
6376 }
6477
@@ -74,15 +87,32 @@ public function issueChallenge(Authenticatable $user, string $method): ?MfaChall
7487 $ challenge ->expires_at = Carbon::now ()->addSeconds ($ ttlSeconds );
7588 $ challenge ->save ();
7689
77- if ($ method === 'email ' ) {
78- (new EmailChannel ($ this ->config ['email ' ] ?? []))->send ($ user , $ code );
79- } else if ($ method === 'sms ' ) {
80- (new SmsChannel ($ this ->config ['sms ' ] ?? []))->send ($ user , $ code );
81- }
90+ $ channel ->send ($ user , $ code );
8291
8392 return $ challenge ;
8493 }
8594
95+ public function registerChannel (MfaChannel $ channel ): void
96+ {
97+ $ this ->registry ->register ($ channel );
98+ }
99+
100+ public function generateTotpQrCodeBase64 (Authenticatable $ user , ?string $ issuer = null , ?string $ label = null , int $ size = 200 ): ?string
101+ {
102+ $ method = $ this ->getMethod ($ user , 'totp ' );
103+ if (! $ method || ! $ method ->secret ) {
104+ return null ;
105+ }
106+
107+ $ issuer = $ issuer ?: Arr::get ($ this ->config , 'totp.issuer ' , 'Laravel ' );
108+ $ label = $ label ?: (method_exists ($ user , 'getEmailForVerification ' ) ? $ user ->getEmailForVerification () : ($ user ->email ?? (string ) $ user ->getAuthIdentifier ()));
109+ $ digits = Arr::get ($ this ->config , 'totp.digits ' , 6 );
110+ $ period = Arr::get ($ this ->config , 'totp.period ' , 30 );
111+
112+ $ otpauth = GoogleTotp::buildOtpAuthUrl ($ method ->secret , $ label , $ issuer , $ digits , $ period );
113+ return QrCodeGenerator::generateBase64Png ($ otpauth , $ size );
114+ }
115+
86116 public function verifyChallenge (Authenticatable $ user , string $ method , string $ code ): bool
87117 {
88118 $ now = Carbon::now ();
0 commit comments