Skip to content

Commit

Permalink
Add auth guards
Browse files Browse the repository at this point in the history
  • Loading branch information
kamorel committed Mar 14, 2023
1 parent f7cdf27 commit 37e1809
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 68 deletions.
38 changes: 38 additions & 0 deletions frontend/src/components/guards/RequireAuth.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { onBeforeMount, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useAuthStore } from '@/store';
import { RouteNames } from '@/utils/constants';
import type { Ref } from 'vue';
// Store
const { getIsAuthenticated } = storeToRefs(useAuthStore());
// State
const ready: Ref<boolean> = ref(false);
// Actions
onBeforeMount( async () => {
const router = useRouter();
if( !getIsAuthenticated.value ) {
router.replace({ name: RouteNames.LOGIN });
}
else {
ready.value = true;
}
});
</script>

<template>
<slot v-if="ready" />
</template>

<style lang="scss" scoped>
h3 {
font-weight: bold;
}
</style>
52 changes: 52 additions & 0 deletions frontend/src/components/guards/RequirePublicOrAuth.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { onBeforeMount, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useAuthStore, useObjectStore } from '@/store';
import { RouteNames } from '@/utils/constants';
import type { Ref } from 'vue';
// Props
type Props = {
objectId: string
};
const props = withDefaults(defineProps<Props>(), {});
// Store
const objectStore = useObjectStore();
const { getIsAuthenticated } = storeToRefs(useAuthStore());
// State
const ready: Ref<boolean> = ref(false);
// Actions
const router = useRouter();
onBeforeMount( async () => {
let isPublic = false;
if( props.objectId ) {
const head = await objectStore.headObject(props.objectId);
isPublic = head?.status === 204;
}
if( !isPublic && !getIsAuthenticated.value ) {
router.replace({ name: RouteNames.LOGIN });
}
else {
ready.value = true;
}
});
</script>

<template>
<slot v-if="ready" />
</template>

<style lang="scss" scoped>
h3 {
font-weight: bold;
}
</style>
2 changes: 2 additions & 0 deletions frontend/src/components/guards/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as RequireAuth } from './RequireAuth.vue';
export { default as RequirePublicOrAuth } from './RequirePublicOrAuth.vue';
24 changes: 22 additions & 2 deletions frontend/src/components/object/ObjectFileDetails.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { onMounted, ref, watch } from 'vue';
import { onMounted, onBeforeMount, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import {
DeleteObjectButton,
Expand All @@ -14,7 +15,7 @@ import {
} from '@/components/object';
import { Button, Dialog } from '@/lib/primevue';
import { useAuthStore, useMetadataStore, useObjectStore, usePermissionStore } from '@/store';
import { Permissions } from '@/utils/constants';
import { Permissions, RouteNames } from '@/utils/constants';
import { ButtonMode } from '@/utils/enums';
import type { Ref } from 'vue';
Expand Down Expand Up @@ -42,12 +43,31 @@ const obj: Ref<COMSObject | undefined> = ref(undefined);
const bucketId: Ref<string> = ref('');
// Actions
const router = useRouter();
const showPermissions = async (objectId: string) => {
permissionsVisible.value = true;
permissionsObjectId.value = objectId;
permissionsObjectName.value = metadataStore.findValue(objectId, 'name') || '';
};
onBeforeMount( async () => {
if( props.objId ) {
const head = await objectStore.headObject(props.objId);
let isPublic = head?.status === 204;
await permissionStore.fetchBucketPermissions({userId: getUserId.value});
await objectStore.fetchObjects({objId: props.objId, userId: getUserId.value});
const obj = objectStore.findObjectById(props.objId);
const bucketId = obj?.bucketId;
if( !isPublic &&
( !obj || !permissionStore.isObjectActionAllowed(obj.id, getUserId.value, Permissions.READ, bucketId) ) ) {
router.replace({ name: RouteNames.FORBIDDEN });
}
}
});
onMounted(() => {
permissionStore.fetchBucketPermissions({ userId: getUserId.value, objectPerms: true });
});
Expand Down
76 changes: 10 additions & 66 deletions frontend/src/views/detail/DetailObjectsView.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { onBeforeMount, ref } from 'vue';
import { useRouter } from 'vue-router';
import ObjectFileDetails from '@/components/object/ObjectFileDetails.vue';
import { useAuthStore, useObjectStore, usePermissionStore } from '@/store';
import { Permissions, RouteNames } from '@/utils/constants';
import type { Ref } from 'vue';
import { RequirePublicOrAuth } from '@/components/guards';
import { ObjectFileDetails } from '@/components/object';
// Props
type Props = {
Expand All @@ -16,67 +9,18 @@ type Props = {
const props = withDefaults(defineProps<Props>(), {});
// Store
const objectStore = useObjectStore();
const permissionStore = usePermissionStore();
const { getIsAuthenticated, getUserId } = storeToRefs(useAuthStore());
// State
const ready: Ref<boolean> = ref(false);
const isPublic: Ref<boolean> = ref(false);
// Actions
onBeforeMount( async () => {
const router = useRouter();
if( props.objId ) {
const head = await objectStore.headObject(props.objId);
isPublic.value = head?.status === 204;
if( isPublic.value && !getIsAuthenticated.value ) {
ready.value = true;
}
else {
if( !getIsAuthenticated.value ) {
router.replace({ name: RouteNames.LOGIN });
}
else {
await permissionStore.fetchBucketPermissions({userId: getUserId.value});
await objectStore.fetchObjects({objId: props.objId, userId: getUserId.value});
const obj = objectStore.findObjectById(props.objId);
const bucketId = obj?.bucketId;
if( !isPublic.value &&
( !obj || !permissionStore.isObjectActionAllowed(obj.id, getUserId.value, Permissions.READ, bucketId) ) ) {
router.replace({ name: RouteNames.FORBIDDEN });
}
else {
ready.value = true;
}
}
}
}
else {
router.replace({ name: RouteNames.FORBIDDEN });
}
});
</script>

<template>
<div v-if="ready">
<div v-if="getIsAuthenticated">
<ObjectFileDetails
v-if="objId"
:obj-id="props.objId"
/>
<div v-else>
<h3>No object provided</h3>
</div>
</div>
<div v-else-if="isPublic && !getIsAuthenticated">
<h3>Public file. COMS API does not currently allow unauthenticated users to fetch data.</h3>
<RequirePublicOrAuth :object-id="props.objectId">
<ObjectFileDetails
v-if="objectId"
:object-id="props.objectId"
/>
<div v-else>
<h3>No object provided</h3>
</div>
</div>
</RequirePublicOrAuth>
</template>

<style lang="scss" scoped>
Expand Down

0 comments on commit 37e1809

Please sign in to comment.