Skip to content

Commit 14b14a6

Browse files
authored
Merge pull request #39 from rabol/master
Add access_code feature
2 parents 2bb03de + 39d2c58 commit 14b14a6

11 files changed

+315
-11
lines changed

.DS_Store

6 KB
Binary file not shown.

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,20 @@ $urlToCustomFunction = MagicLink::create(
160160
)->url;
161161
```
162162

163+
## Protect with an access code
164+
165+
Optionally you can protect the resources with an access code.
166+
You can set the access code with method `protectWithAccessCode`
167+
which accepts an argument with the access code.
168+
169+
```php
170+
$magiclink = MagicLink::create(new DownloadFileAction('private_document.pdf'));
171+
172+
$magiclink->protectWithAccessCode('secret');
173+
174+
$urlToSend = $magiclink->url;
175+
```
176+
163177
## MagicLink link lifetime
164178

165179
By default a link will be available for 72 hours after your creation. We can

databases/.DS_Store

6 KB
Binary file not shown.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class AddAccessCodeToMagicLinksTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::table('magic_links', function (Blueprint $table) {
17+
$table->string('access_code')->nullable();
18+
});
19+
}
20+
21+
/**
22+
* Reverse the migrations.
23+
*
24+
* @return void
25+
*/
26+
public function down()
27+
{
28+
if (Schema::hasColumn('magic_links', 'access_code')) {
29+
Schema::table('magic_links', function (Blueprint $table) {
30+
$table->dropColumn('access_code');
31+
});
32+
}
33+
}
34+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Password protected</title>
5+
6+
<link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css">
7+
8+
<style>
9+
html, body {
10+
height: 100%;
11+
}
12+
13+
body {
14+
margin: 0;
15+
padding: 0;
16+
width: 100%;
17+
display: table;
18+
font-weight: 100;
19+
font-family: 'Lato';
20+
}
21+
22+
.container {
23+
text-align: center;
24+
display: table-cell;
25+
vertical-align: middle;
26+
}
27+
28+
.content {
29+
text-align: center;
30+
display: inline-block;
31+
}
32+
33+
.title {
34+
font-size: 36px;
35+
}
36+
37+
.form-control {
38+
border: 1px solid #ccc;
39+
padding: 10px 20px;
40+
}
41+
42+
.hidden {
43+
display: none;
44+
}
45+
46+
.text-danger {
47+
color: #d9534f;
48+
}
49+
</style>
50+
</head>
51+
<body>
52+
<div class="container">
53+
<div class="content">
54+
<div class="title">Enter access code</div>
55+
56+
<form method="GET">
57+
{{ csrf_field() }}
58+
59+
<div class="form-group">
60+
61+
<input type="password" name="access-code" placeholder="Please enter access code" class="form-control" tabindex="1" autofocus />
62+
@if (Request::get('access-code'))
63+
<div class="text-danger">Access code is wrong</div>
64+
@else
65+
<div class="small help-block">And press enter</div>
66+
@endif
67+
</div>
68+
69+
<input type="submit" class="hidden" />
70+
71+
</form>
72+
</div>
73+
</div>
74+
</body>
75+
</html>

src/.DS_Store

6 KB
Binary file not shown.

src/MagicLink.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Database\Eloquent\Model;
77
use Illuminate\Database\QueryException;
88
use Illuminate\Support\Facades\Event;
9+
use Illuminate\Support\Facades\Hash;
910
use Illuminate\Support\Str;
1011
use MagicLink\Actions\ActionInterface;
1112
use MagicLink\Events\MagicLinkWasCreated;
@@ -87,6 +88,46 @@ public static function create(ActionInterface $action, ?int $lifetime = 4320, ?i
8788
return $magiclink;
8889
}
8990

91+
/**
92+
* Protect the Action with an access code.
93+
*
94+
* @param string $accessCode
95+
* @return self
96+
*/
97+
public function protectWithAccessCode(string $accessCode): self
98+
{
99+
$this->access_code = Hash::make($accessCode);
100+
101+
$this->save();
102+
103+
return $this;
104+
}
105+
106+
/**
107+
* Check if access code is right.
108+
*
109+
* @param string|null $accessCode
110+
* @return bool
111+
*/
112+
public function checkAccessCode(?string $accessCode): bool
113+
{
114+
if ($accessCode === null) {
115+
return false;
116+
}
117+
118+
return Hash::check($accessCode, $this->access_code);
119+
}
120+
121+
/**
122+
* The action was protected with an access code.
123+
*
124+
* @return bool
125+
*/
126+
public function protectedWithAcessCode(): bool
127+
{
128+
return ! is_null($this->access_code ?? null);
129+
}
130+
90131
/**
91132
* Execute Action.
92133
*

src/MagicLinkServiceProvider.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ public function boot()
2222
if ($this->mustLoadRoute()) {
2323
$this->loadRoutesFrom(__DIR__.'/routes.php');
2424
}
25+
26+
// Views
27+
$sourceViewsPath = __DIR__.'/../resources/views';
28+
$this->loadViewsFrom($sourceViewsPath, 'magiclink');
29+
$this->publishes([
30+
$sourceViewsPath => resource_path('views/vendor/magiclink'),
31+
], 'views');
2532
}
2633

2734
protected function mustLoadRoute()

src/Middlewares/MagiclinkMiddleware.php

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace MagicLink\Middlewares;
44

55
use Closure;
6+
use Illuminate\Contracts\Encryption\DecryptException;
67
use Illuminate\Http\Request;
8+
use Illuminate\Support\Facades\Hash;
79
use MagicLink\MagicLink;
810
use MagicLink\Responses\Response;
911

@@ -15,16 +17,56 @@ public function handle(Request $request, Closure $next)
1517

1618
$magicLink = MagicLink::getValidMagicLinkByToken($token);
1719

18-
if ($magicLink) {
19-
$magicLink->visited();
20+
if (! $magicLink) {
21+
return $this->badResponse();
22+
}
23+
24+
if ($magicLink->protectedWithAcessCode()) {
25+
if ($magicLink->checkAccessCode($request->get('access-code'))) {
26+
// access code is valid
27+
return redirect($request->url())->withCookie(
28+
cookie(
29+
'magic-link-access-code',
30+
encrypt($request->get('access-code')),
31+
0,
32+
'/'
33+
)
34+
);
35+
}
36+
37+
try {
38+
$accessCode = decrypt($request->cookie('magic-link-access-code'));
39+
40+
// Validate access_code
41+
if ($magicLink->checkAccessCode($accessCode)) {
42+
$magicLink->visited();
43+
44+
return $next($request);
45+
}
46+
} catch (DecryptException $e) {
47+
// empty value in cookie
48+
}
2049

21-
return $next($request);
50+
return response(view('magiclink::ask-for-access-code-form'), 403);
2251
}
2352

24-
return $this->response();
53+
$magicLink->visited();
54+
55+
return $next($request);
2556
}
2657

27-
protected function response()
58+
// private function isAccessCodeValid(string $token, ?string $accessCode): bool
59+
// {
60+
// if ($accessCode === null) {
61+
// return false;
62+
// }
63+
64+
// $magicLink = MagicLink::getValidMagicLinkByToken($token);
65+
66+
// return Hash::check($accessCode, $magicLink->access_code);
67+
// }
68+
69+
protected function badResponse()
2870
{
2971
$responseClass = config('magiclink.invalid_response.class', Response::class);
3072

src/routes.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,17 @@
33
use Illuminate\Support\Facades\Route;
44
use MagicLink\Middlewares\MagiclinkMiddleware;
55

6-
Route::group(['middleware' => [MagiclinkMiddleware::class, 'web']], function () {
7-
Route::get(
8-
config('magiclink.url.validate_path', 'magiclink').'/{token}',
9-
'MagicLink\Controllers\MagicLinkController@access'
10-
);
11-
});
6+
Route::group(
7+
[
8+
'middleware' => [
9+
MagiclinkMiddleware::class,
10+
'web',
11+
],
12+
],
13+
function () {
14+
Route::get(
15+
config('magiclink.url.validate_path', 'magiclink').'/{token}',
16+
'MagicLink\Controllers\MagicLinkController@access'
17+
);
18+
}
19+
);

0 commit comments

Comments
 (0)