137 global $wgOATHAuthWindowRadius;
139 $token = $data[
'token'];
141 if ( $this->secret[
'mode'] !==
'hotp' ) {
142 throw new DomainException(
'OATHAuth extension does not support non-HOTP tokens' );
148 $key = $store->makeKey(
'oathauth-totp',
'usedtokens', $uid );
149 $lastWindow = (int)$store->get( $key );
152 $results = HOTP::generateByTimeWindow(
153 Base32::decode( $this->secret[
'secret'] ),
154 $this->secret[
'period'], -$wgOATHAuthWindowRadius, $wgOATHAuthWindowRadius
159 $token = preg_replace(
'/\s+/',
'', $token );
161 $clientIP = $user->
getUser()->getRequest()->getIP();
167 foreach ( $results as $window => $result ) {
168 if ( $window > $lastWindow && $result->toHOTP( 6 ) === $token ) {
169 $lastWindow = $window;
172 $logger->info(
'OATHAuth user {user} entered a valid OTP from {clientip}', [
174 'clientip' => $clientIP,
182 $length = count( $this->scratchTokens );
184 if ( $length === 1 && $this->scratchTokens[0] ===
"" ) {
187 for ( $i = 0; $i < $length; $i++ ) {
188 if ( $token === $this->scratchTokens[$i] ) {
190 array_splice( $this->scratchTokens, $i, 1 );
192 $logger->info(
'OATHAuth user {user} used a scratch token from {clientip}', [
194 'clientip' => $clientIP,
198 $module = $auth->getModuleByKey(
'totp' );
204 $userRepo->persist( $user, $clientIP );
217 $this->secret[
'period'] * ( 1 + 2 * $wgOATHAuthWindowRadius )
220 $logger->info(
'OATHAuth user {user} failed OTP/scratch token from {clientip}', [
222 'clientip' => $clientIP,
226 $user->
getUser()->pingLimiter(
'badoath' );