25 use Psr\Log\LoggerInterface;
66 Base32::encode( random_bytes( 10 ) ),
70 $object->regenerateScratchTokens();
82 $data = json_decode( $data,
true );
83 if ( json_last_error() !== JSON_ERROR_NONE ) {
86 return static::newFromArray( $data );
94 if ( !isset( $data[
'secret'] ) || !isset( $data[
'scratch_tokens'] ) ) {
97 return new static( $data[
'secret'], $data[
'scratch_tokens'] );
110 'algorithm' =>
'SHA1',
119 return $this->secret[
'secret'];
136 global $wgOATHAuthWindowRadius;
138 $token = $data[
'token'];
140 if ( $this->secret[
'mode'] !==
'hotp' ) {
141 throw new DomainException(
'OATHAuth extension does not support non-HOTP tokens' );
147 $key = $store->makeKey(
'oathauth-totp',
'usedtokens', $uid );
148 $lastWindow = (int)$store->get( $key );
151 $results = HOTP::generateByTimeWindow(
152 Base32::decode( $this->secret[
'secret'] ),
153 $this->secret[
'period'], -$wgOATHAuthWindowRadius, $wgOATHAuthWindowRadius
158 $token = preg_replace(
'/\s+/',
'', $token );
160 $clientIP = $user->
getUser()->getRequest()->getIP();
166 foreach ( $results as $window => $result ) {
167 if ( $window > $lastWindow && $result->toHOTP( 6 ) === $token ) {
168 $lastWindow = $window;
171 $logger->info(
'OATHAuth user {user} entered a valid OTP from {clientip}', [
173 'clientip' => $clientIP,
181 $length = count( $this->scratchTokens );
183 if ( $length === 1 && $this->scratchTokens[0] ===
"" ) {
186 for ( $i = 0; $i < $length; $i++ ) {
187 if ( $token === $this->scratchTokens[$i] ) {
189 unset( $this->scratchTokens[$i] );
191 $logger->info(
'OATHAuth user {user} used a scratch token from {clientip}', [
193 'clientip' => $clientIP,
197 $module = $auth->getModuleByKey(
'totp' );
201 $userRepo->persist( $user, $clientIP );
214 $this->secret[
'period'] * ( 1 + 2 * $wgOATHAuthWindowRadius )
217 $logger->info(
'OATHAuth user {user} failed OTP/scratch token from {clientip}', [
219 'clientip' => $clientIP,
223 $user->
getUser()->pingLimiter(
'badoath' );
231 for ( $i = 0; $i < 10; $i++ ) {
245 $token = preg_replace(
'/\s+/',
'', $token );
246 return in_array( $token, $this->scratchTokens,
true );