Skip to content

Commit abff1f4

Browse files
committed
Update OTP table schema and refactor DatabaseStorage for improved readability
1 parent 52e5fba commit abff1f4

File tree

3 files changed

+49
-46
lines changed

3 files changed

+49
-46
lines changed

database/migrations/2024_01_01_000000_create_simple_otp_codes_table.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ public function up(): void
1212
$table->id();
1313
$table->string('identifier')->index();
1414
$table->string('code');
15-
$table->timestamp('created_at');
16-
$table->timestamp('expires_at')->index();
15+
$table->dateTime('created_at');
16+
$table->dateTime('expires_at')->index();
1717
$table->integer('attempts')->default(0);
1818
$table->boolean('verified')->default(false);
1919
$table->json('metadata')->nullable();
20-
20+
2121
$table->index(['identifier', 'expires_at']);
2222
});
2323
}

src/OTPService.php

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
namespace Aslnbxrz\SimpleOTP;
44

5-
use Illuminate\Support\Facades\Cache;
65
use Illuminate\Support\Facades\RateLimiter;
7-
use Aslnbxrz\SimpleOTP\Contracts\OTPDeliveryContract;
6+
use Aslnbxrz\SimpleOTP\Exceptions\OTPException;
87
use Aslnbxrz\SimpleOTP\Contracts\OTPServiceContract;
98
use Aslnbxrz\SimpleOTP\Contracts\OTPStorageContract;
10-
use Aslnbxrz\SimpleOTP\Exceptions\OTPException;
9+
use Aslnbxrz\SimpleOTP\Contracts\OTPDeliveryContract;
1110
use Aslnbxrz\SimpleOTP\Exceptions\OTPDeliveryException;
1211

1312
class OTPService implements OTPServiceContract
@@ -18,9 +17,9 @@ class OTPService implements OTPServiceContract
1817

1918
public function __construct(OTPStorageContract $storage, OTPDeliveryContract $delivery, array $config)
2019
{
21-
$this->storage = $storage;
20+
$this->storage = $storage;
2221
$this->delivery = $delivery;
23-
$this->config = $config;
22+
$this->config = $config;
2423
}
2524

2625
public function generate(string $identifier, string $recipient, array $options = []): array
@@ -35,12 +34,12 @@ public function generate(string $identifier, string $recipient, array $options =
3534

3635
// Store OTP
3736
$metadata = [
38-
'recipient' => $recipient,
37+
'recipient' => $recipient,
3938
'delivery_driver' => $this->delivery->getDriver(),
40-
'options' => $options,
39+
'options' => $options,
4140
];
4241

43-
$ttlMinutes = $this->config['otp']['ttl'] ?? 5;
42+
$ttlMinutes = $this->config['otp']['ttl'] ?? 5;
4443
$storeResult = $this->storage->store($identifier, $code, $ttlMinutes, $metadata);
4544

4645
if (!$storeResult) {
@@ -53,15 +52,16 @@ public function generate(string $identifier, string $recipient, array $options =
5352
} catch (OTPDeliveryException $e) {
5453
// Clean up stored OTP if delivery fails
5554
$this->storage->delete($identifier);
55+
5656
throw $e;
5757
}
5858

5959
// Increment rate limiting counter
6060
$this->incrementRateLimit($identifier);
6161

6262
return [
63-
'success' => true,
64-
'message' => $this->getMessage('sent'),
63+
'success' => true,
64+
'message' => $this->getMessage('sent'),
6565
'identifier' => $identifier,
6666
'expires_at' => now()->addMinutes($ttlMinutes),
6767
];
@@ -84,6 +84,7 @@ public function verify(string $identifier, string $code): bool
8484
$maxAttempts = $this->config['otp']['max_attempts'] ?? 3;
8585
if ($otpData['attempts'] >= $maxAttempts) {
8686
$this->storage->delete($identifier);
87+
8788
throw new OTPException($this->getMessage('max_attempts'));
8889
}
8990

@@ -105,7 +106,7 @@ public function resend(string $identifier, string $recipient, array $options = [
105106
{
106107
// Check if OTP exists
107108
$existingOtp = $this->storage->get($identifier);
108-
109+
109110
if ($existingOtp && $existingOtp['verified']) {
110111
throw new OTPException($this->getMessage('verified'));
111112
}
@@ -120,25 +121,26 @@ public function resend(string $identifier, string $recipient, array $options = [
120121
public function exists(string $identifier): bool
121122
{
122123
$otpData = $this->storage->get($identifier);
124+
123125
return $otpData !== null && !$otpData['verified'];
124126
}
125127

126128
public function info(string $identifier): ?array
127129
{
128130
$otpData = $this->storage->get($identifier);
129-
131+
130132
if (!$otpData) {
131133
return null;
132134
}
133135

134136
return [
135137
'identifier' => $identifier,
136-
'recipient' => $otpData['recipient'] ?? null,
138+
'recipient' => $otpData['recipient'] ?? null,
137139
'created_at' => $otpData['created_at'],
138140
'expires_at' => $otpData['expires_at'],
139-
'attempts' => $otpData['attempts'],
140-
'verified' => $otpData['verified'],
141-
'expired' => now()->timestamp > $otpData['expires_at'],
141+
'attempts' => $otpData['attempts'],
142+
'verified' => $otpData['verified'],
143+
'expired' => now()->timestamp > $otpData['expires_at'],
142144
];
143145
}
144146

@@ -149,7 +151,7 @@ public function delete(string $identifier): bool
149151

150152
protected function generateCode(): string
151153
{
152-
$type = $this->config['otp']['type'] ?? 'numeric';
154+
$type = $this->config['otp']['type'] ?? 'numeric';
153155
$length = $this->config['otp']['length'] ?? 6;
154156

155157
switch ($type) {
@@ -168,30 +170,31 @@ protected function generateNumericCode(int $length): string
168170
{
169171
$min = pow(10, $length - 1);
170172
$max = pow(10, $length) - 1;
173+
171174
return (string) random_int($min, $max);
172175
}
173176

174177
protected function generateAlphanumericCode(int $length): string
175178
{
176179
$characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
177-
$code = '';
178-
180+
$code = '';
181+
179182
for ($i = 0; $i < $length; $i++) {
180183
$code .= $characters[random_int(0, strlen($characters) - 1)];
181184
}
182-
185+
183186
return $code;
184187
}
185188

186189
protected function generateAlphaCode(int $length): string
187190
{
188191
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
189-
$code = '';
190-
192+
$code = '';
193+
191194
for ($i = 0; $i < $length; $i++) {
192195
$code .= $characters[random_int(0, strlen($characters) - 1)];
193196
}
194-
197+
195198
return $code;
196199
}
197200

@@ -204,6 +207,7 @@ protected function isRateLimited(string $identifier): bool
204207

205208
$key = "simple_otp_rate_limit:{$identifier}";
206209
$max = $rateLimit['max_attempts'] ?? 5;
210+
207211
return RateLimiter::tooManyAttempts($key, $max);
208212
}
209213

@@ -214,9 +218,9 @@ protected function incrementRateLimit(string $identifier): void
214218
return;
215219
}
216220

217-
$key = "simple_otp_rate_limit:{$identifier}";
221+
$key = "simple_otp_rate_limit:{$identifier}";
218222
$decayMinutes = $rateLimit['decay_minutes'] ?? 60;
219-
223+
220224
RateLimiter::hit($key, $decayMinutes * 60);
221225
}
222226

src/Storage/DatabaseStorage.php

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22

33
namespace Aslnbxrz\SimpleOTP\Storage;
44

5-
use Aslnbxrz\SimpleOTP\Contracts\OTPStorageContract;
65
use Illuminate\Database\ConnectionInterface;
7-
use Illuminate\Support\Facades\DB;
6+
use Aslnbxrz\SimpleOTP\Contracts\OTPStorageContract;
87

98
class DatabaseStorage implements OTPStorageContract
109
{
@@ -14,7 +13,7 @@ class DatabaseStorage implements OTPStorageContract
1413
public function __construct(ConnectionInterface $connection, string $table = 'simple_otp_codes')
1514
{
1615
$this->connection = $connection;
17-
$this->table = $table;
16+
$this->table = $table;
1817
}
1918

2019
public function store(string $identifier, string $code, int $ttl, array $metadata = []): bool
@@ -23,12 +22,12 @@ public function store(string $identifier, string $code, int $ttl, array $metadat
2322

2423
$data = [
2524
'identifier' => $identifier,
26-
'code' => $code,
25+
'code' => $code,
2726
'created_at' => $now,
2827
'expires_at' => $now->copy()->addMinutes($ttl),
29-
'attempts' => 0,
30-
'verified' => false,
31-
'metadata' => json_encode($metadata),
28+
'attempts' => 0,
29+
'verified' => false,
30+
'metadata' => json_encode($metadata),
3231
];
3332

3433
return $this->connection->table($this->table)->insert($data);
@@ -46,12 +45,12 @@ public function get(string $identifier): ?array
4645
}
4746

4847
return [
49-
'code' => $record->code,
50-
'created_at' => $record->created_at->timestamp,
51-
'expires_at' => $record->expires_at->timestamp,
52-
'attempts' => $record->attempts,
53-
'verified' => (bool)$record->verified,
54-
'metadata' => json_decode($record->metadata, true) ?: [],
48+
'code' => $record->code,
49+
'created_at' => $record->created_at,
50+
'expires_at' => $record->expires_at,
51+
'attempts' => $record->attempts,
52+
'verified' => (bool) $record->verified,
53+
'metadata' => json_decode($record->metadata, true) ?: [],
5554
];
5655
}
5756

@@ -69,7 +68,7 @@ public function update(string $identifier, array $metadata): bool
6968
->first();
7069

7170
if ($existingRecord) {
72-
$existingMetadata = json_decode($existingRecord->metadata, true) ?: [];
71+
$existingMetadata = json_decode($existingRecord->metadata, true) ?: [];
7372
$existingMetadata[$key] = $value;
7473
$updateData['metadata'] = json_encode($existingMetadata);
7574
}
@@ -81,15 +80,15 @@ public function update(string $identifier, array $metadata): bool
8180
}
8281

8382
return $this->connection->table($this->table)
84-
->where('identifier', $identifier)
85-
->update($updateData) > 0;
83+
->where('identifier', $identifier)
84+
->update($updateData) > 0;
8685
}
8786

8887
public function delete(string $identifier): bool
8988
{
9089
return $this->connection->table($this->table)
91-
->where('identifier', $identifier)
92-
->delete() > 0;
90+
->where('identifier', $identifier)
91+
->delete() > 0;
9392
}
9493

9594
public function cleanup(): int

0 commit comments

Comments
 (0)