- Frontend restriction shared page

This commit is contained in:
Čarodej
2022-01-06 11:05:49 +01:00
parent 05f6023053
commit 8d53ed1531
17 changed files with 188 additions and 36 deletions

View File

@@ -53,7 +53,7 @@
"/chunks/invitation.js": "/chunks/invitation.js?id=b3a04d44ea7e75c6203a",
"/chunks/invoices.js": "/chunks/invoices.js?id=2032e4f8e4f5ed58b8b4",
"/chunks/my-shared-items.js": "/chunks/my-shared-items.js?id=ef0a2dbe808eaee42c1f",
"/chunks/not-found.js": "/chunks/not-found.js?id=034287ee0ecb036320d3",
"/chunks/not-found.js": "/chunks/not-found.js?id=9b179edd89e9b0544566",
"/chunks/page-edit.js": "/chunks/page-edit.js?id=1b8c9a0eee76fcb52f12",
"/chunks/pages.js": "/chunks/pages.js?id=8c6772e3224fadca2bf2",
"/chunks/plan.js": "/chunks/plan.js?id=f62a5bd64fb706b2f0e2",
@@ -75,7 +75,7 @@
"/chunks/settings-storage.js": "/chunks/settings-storage.js?id=76b45c336e8e12b23e81",
"/chunks/settings~chunks/settings-password.js": "/chunks/settings~chunks/settings-password.js?id=aafc9cd6aa47b01bc25a",
"/chunks/setup-wizard.js": "/chunks/setup-wizard.js?id=651d5accf401908724c5",
"/chunks/shared.js": "/chunks/shared.js?id=387e9dc2cb6e3e328cf4",
"/chunks/shared.js": "/chunks/shared.js?id=db60726012b6d246bd77",
"/chunks/shared-with-me.js": "/chunks/shared-with-me.js?id=cf39d503eef93bcc7f1c",
"/chunks/shared-with-me~chunks/team-folders.js": "/chunks/shared-with-me~chunks/team-folders.js?id=abf65131397ea2b12355",
"/chunks/shared/authenticate.js": "/chunks/shared/authenticate.js?id=e19e444844d1495d900f",
@@ -217,5 +217,29 @@
"/js/main.fcf019dfae2cac8e0432.hot-update.js": "/js/main.fcf019dfae2cac8e0432.hot-update.js",
"/js/main.b99796b9cd80dfca9231.hot-update.js": "/js/main.b99796b9cd80dfca9231.hot-update.js",
"/js/main.ff162a01c1b21836ee9f.hot-update.js": "/js/main.ff162a01c1b21836ee9f.hot-update.js",
"/js/main.7a46e4ea987d72347892.hot-update.js": "/js/main.7a46e4ea987d72347892.hot-update.js"
"/js/main.7a46e4ea987d72347892.hot-update.js": "/js/main.7a46e4ea987d72347892.hot-update.js",
"/chunks/shared.e292a21450a2e96c5b77.hot-update.js": "/chunks/shared.e292a21450a2e96c5b77.hot-update.js",
"/chunks/shared.ea4e7bbd3ce9f55a2c8e.hot-update.js": "/chunks/shared.ea4e7bbd3ce9f55a2c8e.hot-update.js",
"/chunks/shared.836f769daafe640518ac.hot-update.js": "/chunks/shared.836f769daafe640518ac.hot-update.js",
"/js/main.d457be736ef017a782ea.hot-update.js": "/js/main.d457be736ef017a782ea.hot-update.js",
"/chunks/platform~chunks/shared.d457be736ef017a782ea.hot-update.js": "/chunks/platform~chunks/shared.d457be736ef017a782ea.hot-update.js",
"/chunks/shared.d457be736ef017a782ea.hot-update.js": "/chunks/shared.d457be736ef017a782ea.hot-update.js",
"/js/main.83361deb74c3e1859144.hot-update.js": "/js/main.83361deb74c3e1859144.hot-update.js",
"/chunks/admin~chunks/platform.83361deb74c3e1859144.hot-update.js": "/chunks/admin~chunks/platform.83361deb74c3e1859144.hot-update.js",
"/chunks/platform.83361deb74c3e1859144.hot-update.js": "/chunks/platform.83361deb74c3e1859144.hot-update.js",
"/chunks/shared.83361deb74c3e1859144.hot-update.js": "/chunks/shared.83361deb74c3e1859144.hot-update.js",
"/chunks/shared.3b938ab55dc98ab07bd9.hot-update.js": "/chunks/shared.3b938ab55dc98ab07bd9.hot-update.js",
"/js/main.1f3af2652193f43c092d.hot-update.js": "/js/main.1f3af2652193f43c092d.hot-update.js",
"/js/main.fef96a82e13da818af79.hot-update.js": "/js/main.fef96a82e13da818af79.hot-update.js",
"/chunks/app-setup~chunks/billings-detail~chunks/create-new-password~chunks/database~chunks/email-veri~2c1222b7.js": "/chunks/app-setup~chunks/billings-detail~chunks/create-new-password~chunks/database~chunks/email-veri~2c1222b7.js?id=f8d41224222e2bd2040e",
"/chunks/temporary-unavailable.js": "/chunks/temporary-unavailable.js?id=2269ad0b9a010b240838",
"/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~8c6958f5.js": "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~8c6958f5.js?id=b94057ad23d11b238e2b",
"/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~c31998a3.js": "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~c31998a3.js?id=78abc0680fedc29e1146",
"/js/main.4e470711fec628ada904.hot-update.js": "/js/main.4e470711fec628ada904.hot-update.js",
"/chunks/temporary-unavailable.4e470711fec628ada904.hot-update.js": "/chunks/temporary-unavailable.4e470711fec628ada904.hot-update.js",
"/chunks/temporary-unavailable.eb45683c53ba28a1beaa.hot-update.js": "/chunks/temporary-unavailable.eb45683c53ba28a1beaa.hot-update.js",
"/js/main.819e5cdfad5c00b05e6a.hot-update.js": "/js/main.819e5cdfad5c00b05e6a.hot-update.js",
"/chunks/not-found.819e5cdfad5c00b05e6a.hot-update.js": "/chunks/not-found.819e5cdfad5c00b05e6a.hot-update.js",
"/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~91d4a521.js": "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~91d4a521.js?id=b563ab4d2bf1a17f0fa5",
"/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~af91ece5.js": "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~af91ece5.js?id=9a44c9cf620730dc67d5"
}

View File

@@ -30,7 +30,16 @@ const routesIndex = [
name: 'NotFound',
path: '/not-found',
component: () =>
import(/* webpackChunkName: "chunks/not-found-shared" */ '../views/NotFound'),
import(/* webpackChunkName: "chunks/not-found" */ '../views/NotFound'),
meta: {
requiresAuth: false
},
},
{
name: 'TemporaryUnavailable',
path: '/temporary-unavailable',
component: () =>
import(/* webpackChunkName: "chunks/temporary-unavailable" */ '../views/TemporaryUnavailable'),
meta: {
requiresAuth: false
},

View File

@@ -8,7 +8,7 @@
<home-icon size="17"/>
</div>
<div class="label">
{{ $t('sidebar.home') }}
{{ $t('Home') }}
</div>
</a>
</div>
@@ -75,7 +75,13 @@ export default {
},
methods: {
goHome() {
this.$router.replace({name: 'Public', params: {token: this.$route.params.token, id: this.sharedDetail.item_id}})
this.$router.replace({
name: 'Public',
params: {
token: this.sharedDetail.data.attributes.token,
id: this.sharedDetail.data.attributes.item_id
}
})
},
dragLeave() {
this.area = false

View File

@@ -1,12 +1,10 @@
<template>
<AuthContentWrapper ref="auth">
<AuthContent name="not-found" :visible="true">
<AuthContent :visible="true">
<Headline
:title="$t('page_shared_404.title')"
:description="$t('page_shared_404.subtitle')"
/>
<span class="additional-link">{{ $t('page_registration.have_an_account') }}
<router-link :to="{name: 'SignIn'}">
{{ $t('page_forgotten_password.password_remember_button') }}
@@ -18,32 +16,18 @@
<script>
import AuthContentWrapper from '/resources/js/components/Auth/AuthContentWrapper'
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
import AuthContent from '/resources/js/components/Auth/AuthContent'
import AuthButton from '/resources/js/components/Auth/AuthButton'
import {required} from 'vee-validate/dist/rules'
import Headline from "./Auth/Headline"
import {mapGetters} from 'vuex'
export default {
name: 'NotFound',
components: {
AuthContentWrapper,
ValidationProvider,
ValidationObserver,
AuthContent,
AuthButton,
Headline,
required,
},
computed: {
...mapGetters(['config']),
},
data() {
return {
isLoading: false,
}
}
}
</script>

View File

@@ -35,7 +35,7 @@
<MobileToolbar />
<!--File list & info sidebar-->
<!--File list & info sidebar-->
<div class="flex space-x-6 md:overflow-hidden md:h-full">
<router-view

View File

@@ -0,0 +1,38 @@
<template>
<AuthContentWrapper ref="auth">
<AuthContent :visible="true">
<Headline
:title="$t('Temporary Unavailable')"
:description="$t('Unfortunately, this shared link is temporary unavailable. Please try it later.')"
/>
<span class="additional-link">{{ $t('page_registration.have_an_account') }}
<router-link :to="{name: 'SignIn'}">
{{ $t('page_forgotten_password.password_remember_button') }}
</router-link>
</span>
</AuthContent>
</AuthContentWrapper>
</template>
<script>
import AuthContentWrapper from '/resources/js/components/Auth/AuthContentWrapper'
import AuthContent from '/resources/js/components/Auth/AuthContent'
import AuthButton from '/resources/js/components/Auth/AuthButton'
import Headline from "./Auth/Headline"
export default {
name: 'NotFound',
components: {
AuthContentWrapper,
AuthContent,
AuthButton,
Headline,
},
}
</script>
<style scoped lang="scss">
@import '/resources/sass/vuefilemanager/_auth';
</style>

View File

@@ -43,4 +43,9 @@ class DefaultRestrictionsEngine implements RestrictionsEngine
{
return resolve(CheckMaxTeamMembersLimitAction::class)($user, $newInvites);
}
public function canVisitShared(User $user): bool
{
return true;
}
}

View File

@@ -38,4 +38,9 @@ class FixedBillingRestrictionsEngine implements RestrictionsEngine
{
return resolve(CheckMaxTeamMembersLimitAction::class)($user, $newInvites);
}
public function canVisitShared(User $user): bool
{
return true;
}
}

View File

@@ -34,4 +34,10 @@ class MeteredBillingRestrictionsEngine implements RestrictionsEngine
{
return true;
}
public function canVisitShared(User $user): bool
{
// Disable share visit when user has more than 3 failed payments
return ! ($user->failedPayments()->count() >= 3);
}
}

View File

@@ -14,4 +14,6 @@ interface RestrictionsEngine
public function canCreateTeamFolder(User $user): bool;
public function canInviteTeamMembers(User $user, array $newInvites = []): bool;
public function canVisitShared(User $user): bool;
}

View File

@@ -2,6 +2,7 @@
namespace Domain\Browsing\Controllers;
use Domain\Files\Models\File;
use Domain\Folders\Resources\FolderResource;
use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder;
use Domain\Files\Resources\FilesCollection;
@@ -30,6 +31,7 @@ class VisitorBrowseFolderController
// Check if user can get directory
($this->verifyAccessToItem)($id, $shared);
// Get requested folder
$requestedFolder = Folder::findOrFail($id);
// Get files and folders
@@ -49,7 +51,7 @@ class VisitorBrowseFolderController
return [
'folders' => new FolderCollection($folders),
'files' => new FilesCollection($files),
'root' => $requestedFolder,
'root' => new FolderResource($requestedFolder),
];
}
}

View File

@@ -1,6 +1,7 @@
<?php
namespace Domain\Sharing\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Domain\Files\Models\File;
use Domain\Sharing\Models\Share;
@@ -16,12 +17,16 @@ class SharePublicIndexController extends Controller
*/
public function __construct(
public RecordDownloadAction $recordDownload,
) {
}
) {}
public function __invoke(
Share $share,
): View | StreamedResponse {
): View | StreamedResponse | RedirectResponse {
// Check if user can see shared record
if (! $share->user->canVisitShared()) {
return redirect('/temporary-unavailable');
}
// Delete share_session if exist
if ($share->is_protected) {
cookie()->queue('share_session', '', -1);

View File

@@ -1,7 +1,9 @@
<?php
namespace Domain\Sharing\Controllers;
use Illuminate\View\View;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Domain\Sharing\Models\Share;
use App\Http\Controllers\Controller;
@@ -12,7 +14,8 @@ class WebCrawlerOpenGraphController extends Controller
*/
public function __invoke(
Share $share
): View {
): Application|Factory|View
{
$namespace = match ($share->type) {
'folder' => 'Domain\\Folders\\Models\\Folder',
'file' => 'Domain\\Files\\Models\\File',

View File

@@ -235,4 +235,23 @@ class DefaultRestrictionsTest extends TestCase
->get("file/$file->name/$share->token")
->assertStatus(404);
}
/**
* @test
*/
public function it_can_get_share_page()
{
$user = User::factory()
->create();
$share = Share::factory()
->create([
'user_id' => $user->id,
'type' => 'folder',
'is_protected' => false,
]);
$this->get("/share/$share->token")
->assertViewIs('index');
}
}

View File

@@ -196,4 +196,23 @@ class FixedBillingRestrictionsTest extends TestCase
->get("file/$file->name/$share->token")
->assertStatus(404);
}
/**
* @test
*/
public function it_can_get_share_page()
{
$user = User::factory()
->create();
$share = Share::factory()
->create([
'user_id' => $user->id,
'type' => 'folder',
'is_protected' => false,
]);
$this->get("/share/$share->token")
->assertViewIs('index');
}
}

View File

@@ -213,4 +213,24 @@ class MeteredBillingRestrictionsTest extends TestCase
->get("file/$file->name/$share->token")
->assertStatus(404);
}
/**
* @test
*/
public function it_cant_get_share_page()
{
$user = User::factory()
->hasFailedpayments(3)
->create();
$share = Share::factory()
->create([
'user_id' => $user->id,
'type' => 'folder',
'is_protected' => false,
]);
$this->get("/share/$share->token")
->assertRedirect('/temporary-unavailable');
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace Tests\Domain\Sharing;
use Tests\TestCase;
@@ -43,8 +44,12 @@ class VisitorBrowseTest extends TestCase
*/
public function it_get_share_page()
{
$user = User::factory()
->create();
$share = Share::factory()
->create([
'user_id' => $user->id,
'type' => 'folder',
'is_protected' => false,
]);
@@ -69,7 +74,7 @@ class VisitorBrowseTest extends TestCase
public function it_try_to_get_deleted_share_page()
{
$this->get('/share/19ZMPNiass4ZqWwQ')
->assertNotFound(404);
->assertNotFound();
}
/**
@@ -188,7 +193,7 @@ class VisitorBrowseTest extends TestCase
}
// Check public shared item
if (! $is_protected) {
if (!$is_protected) {
$this->getJson("/api/browse/folders/$root->id/$share->token")
->assertStatus(200)
->assertJsonFragment([
@@ -303,7 +308,7 @@ class VisitorBrowseTest extends TestCase
}
// Check public shared item
if (! $is_protected) {
if (!$is_protected) {
$this->getJson("/api/browse/navigation/$share->token")
->assertStatus(200)
->assertExactJson($tree);
@@ -355,7 +360,7 @@ class VisitorBrowseTest extends TestCase
}
// Check public shared item
if (! $is_protected) {
if (!$is_protected) {
$this->getJson("/api/browse/search/$share->token?query=doc")
->assertStatus(200)
->assertJsonFragment([
@@ -406,7 +411,7 @@ class VisitorBrowseTest extends TestCase
}
// Check public shared item
if (! $is_protected) {
if (!$is_protected) {
$this->getJson("/api/browse/search/$share->token?query=doc")
->assertStatus(200)
->assertJsonFragment([]);
@@ -453,7 +458,7 @@ class VisitorBrowseTest extends TestCase
}
// Check public shared item
if (! $is_protected) {
if (!$is_protected) {
$this->getJson("/api/browse/file/$share->token")
->assertStatus(200)
->assertJsonFragment([