Passed
Push — master ( e56f7d...dff054 )
by Jean-Christophe
20:36
created

Auth2FATrait::confirm()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 11
ccs 0
cts 9
cp 0
rs 9.9666
cc 2
nc 2
nop 0
crap 6
1
<?php
2
3
namespace Ubiquity\controllers\auth\traits;
4
5
use Ubiquity\controllers\auth\AuthFiles;
6
use Ubiquity\utils\flash\FlashMessage;
7
use Ubiquity\utils\http\USession;
8
use Ubiquity\utils\http\URequest;
9
10
/**
11
 * 
12
 * Ubiquity\controllers\auth\traits$Auth2FATrait
13
 * This class is part of Ubiquity
14
 * @author jc
15
 * @version 1.0.0
16
 * 
17
 * @property bool $_invalid
18
 * @property \Ajax\php\ubiquity\JsUtils $jquery
19
 *
20
 */
21
trait Auth2FATrait {
22
23
	private static $TWO_FA_KEY='2FA-infos';
24
25
26
	abstract protected function fMessage(FlashMessage $fMessage, $id = null):string;
27
28
	abstract protected function _getFiles(): AuthFiles;
29
30
	abstract protected function getBaseUrl():string;
31
32
	abstract protected function authLoadView($viewName, $vars = [ ]):void;
33
34
	abstract protected function useAjax():bool;
35
36
	abstract public function _getBodySelector():string;
37
38
	abstract public function _getUserSessionKey():string;
39
40
	abstract protected function onConnect($connected);
41
42
	abstract protected function initializeAuth();
43
44
	abstract protected function finalizeAuth();
45
46
	/**
47
	 * To override for defining a new action when 2FA code is invalid.
48
	 */
49
	protected function onBad2FACode():void{
50
		$this->bad2FACode();
51
	}
52
53
	/**
54
	 * To override
55
	 * Send the 2FA code to the user (email, sms, phone call...)
56
	 * @param string $code
57
	 * @param mixed $connected
58
	 */
59
	protected function _send2FACode(string $code,$connected):void{
60
61
	}
62
63
	/**
64
	 * To override
65
	 * Returns true for a two factor authentification for this account.
66
	 * @param mixed $accountValue
67
	 * @return bool
68
	 */
69 1
	protected function has2FA($accountValue=null):bool{
70 1
		return false;
71
	}
72
73
	/**
74
	 * To override
75
	 * Returns the default size for generated tokens.
76
	 * @return int
77
	 */
78
	protected function getTokenSize():int{
79
		return 6;
80
	}
81
82
	/**
83
	 * Generates a new random 2FA code.
84
	 * You have to override this basic implementation.
85
	 * @return string
86
	 * @throws \Exception
87
	 */
88
	protected function generate2FACode():string{
89
		return \bin2hex ( \random_bytes ($this->getTokenSize()));
90
	}
91
92
	/**
93
	 * Returns the code prefix (which should not be entered by the user).
94
	 * @return string
95
	 */
96
	protected function towFACodePrefix():string{
97
		return 'U-';
98
	}
99
100
101
	/**
102
	 * Returns the default validity duration of a generated 2FA code.
103
	 * @return \DateInterval
104
	 */
105
	protected function twoFACodeDuration():\DateInterval{
106
		return new \DateInterval('PT5M');
107
	}
108
109
	/**
110
	 * To override for modifying the 2FA panel message.
111
	 * @param FlashMessage $fMessage
112
	 */
113
	protected function twoFAMessage(FlashMessage $fMessage){
114
115
	}
116
	/**
117
	 * To override
118
	 * @param FlashMessage $fMessage
119
	 */
120
	protected function newTwoFACodeMessage(FlashMessage $fMessage){
121
122
	}
123
124
	/**
125
	 * To override for modifying the message displayed if the 2FA code is bad.
126
	 * @param FlashMessage $fMessage
127
	 */
128
	protected function twoFABadCodeMessage(FlashMessage $fMessage){
129
130
	}
131
132
	/**
133
	 * To override for a more secure 2FA code.
134
	 * @param string $secret
135
	 * @param string $userInput
136
	 * @return bool
137
	 */
138
	protected function check2FACode(string $secret,string $userInput):bool{
139
		return $secret===$userInput;
140
	}
141
142
	/**
143
	 * @noRoute
144
	 */
145
	#[\Ubiquity\attributes\items\router\NoRoute]
146
	public function bad2FACode():void{
147
		$this->confirm();
148
		$fMessage = new FlashMessage ( 'Invalid 2FA code!', 'Two Factor Authentification', 'warning', 'warning circle' );
149
		$this->twoFABadCodeMessage( $fMessage );
150
		$message = $this->fMessage ( $fMessage, 'bad-code' );
151
		$this->authLoadView ( $this->_getFiles ()->getViewBadTwoFACode(), [ '_message' => $message,'url' => $this->getBaseUrl ().'/sendNew2FACode','bodySelector' => '#bad-two-fa','_btCaption' => 'Send new code' ] );
152
	}
153
154
	/**
155
	 * @noRoute
156
	 */
157
	#[\Ubiquity\attributes\items\router\NoRoute]
158
	public function confirm(){
159
		$fMessage = new FlashMessage( 'Enter the rescue code and validate.', 'Two factor Authentification', 'info', 'key' );
160
		$this->twoFAMessage ( $fMessage );
161
		$message = $this->fMessage ( $fMessage );
162
		if($this->useAjax()){
163
			$frm=$this->jquery->semantic()->htmlForm('frm-valid-code');
164
			$frm->addExtraFieldRule('code','empty');
165
			$frm->setValidationParams(['inline'=>true,'on'=>'blur']);
166
		}
167
		$this->authLoadView ( $this->_getFiles ()->getViewStepTwo(), [ '_message' => $message,'submitURL' => $this->getBaseUrl ().'/submitCode','bodySelector' => $this->_getBodySelector(),'prefix'=>$this->towFACodePrefix() ] );
168
	}
169
	
170
	protected function save2FACode():array{
171
		$code=$this->generate2FACode();
172
		$expire=(new \DateTime())->add($this->twoFACodeDuration());
173
		$codeInfos=USession::get(self::$TWO_FA_KEY,compact('code','expire'));
174
		USession::set(self::$TWO_FA_KEY,$codeInfos);
175
		return $codeInfos;
176
	}
177
	
178
	/**
179
	 * Submits the 2FA code in post request.
180
	 * 
181
	 * @post
182
	 */
183
	#[\Ubiquity\attributes\items\router\Post]
184
	public function submitCode(){
185
		if(URequest::isPost() && USession::exists(self::$TWO_FA_KEY)){
186
			$twoFAInfos=USession::get(self::$TWO_FA_KEY);
187
			$expired=$twoFAInfos['expire']<new \DateTime();
188
			if(!$expired && $this->check2FACode($twoFAInfos['code'],URequest::post('code'))){
189
				$this->onConnect(USession::get($this->_getUserSessionKey().'-2FA'));
190
			}
191
			else{
192
				$this->_invalid=true;
193
				$this->initializeAuth();
194
				$this->onBad2FACode();
195
				$this->finalizeAuth();
196
			}
197
		}
198
	}
199
200
	/**
201
	 * @noRoute
202
	 */
203
	#[\Ubiquity\attributes\items\router\NoRoute]
204
	public function send2FACode(){
205
		$codeInfos=$this->save2FACode();
206
		$this->_send2FACode($codeInfos['code'], USession::get($this->_getUserSessionKey().'-2FA'));
207
	}
208
	
209
	public function sendNew2FACode(){
210
		$this->send2FACode();
211
		$fMessage = new FlashMessage ( 'A new code was submited.', 'Two factor Authentification', 'success', 'key' );
212
		$this->newTwoFACodeMessage ( $fMessage );
213
		echo $this->fMessage ( $fMessage );
214
	}
215
216
}
217
218