Skip to content

Commit

Permalink
Merge pull request #118 from buggregator/feature/auth
Browse files Browse the repository at this point in the history
Added OAuth0 authentication support on the backend.
  • Loading branch information
butschster authored Apr 9, 2024
2 parents 6c71c24 + 727647e commit 25b9782
Show file tree
Hide file tree
Showing 15 changed files with 247 additions and 29 deletions.
16 changes: 16 additions & 0 deletions layouts/blank.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div class="main-layout">
<slot />
</div>
</template>

<script lang="ts">
</script>

<style lang="scss" scoped>
@import "assets/mixins";
.main-layout {
@apply flex min-h-screen items-stretch relative;
}
</style>
14 changes: 5 additions & 9 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class="main-layout__sidebar"
:api-version="apiVersion"
:client-version="clientVersion"
:profile="profile"
/>

<div class="main-layout__content">
Expand Down Expand Up @@ -34,10 +35,11 @@ export default defineComponent({
const { themeType, isFixedHeader } = storeToRefs(settingsStore);
const {
api: { getVersion },
api: { getVersion, getProfile },
} = useSettings();
const apiVersion = await getVersion();
const profile = await getProfile();
const { events } = useEvents();
Expand All @@ -55,6 +57,7 @@ export default defineComponent({
? `v${apiVersion}`
: `@${apiVersion}`,
clientVersion,
profile,
};
},
});
Expand All @@ -69,10 +72,7 @@ export default defineComponent({
.main-layout__sidebar {
@apply w-10 md:w-14 lg:w-16 flex-none border-r border-gray-200 dark:border-gray-700 z-50 w-full h-full sticky top-0 h-screen max-h-screen;
}
.main-layout__header {
@apply flex-none w-full h-10;
@include layout-sidebar;
}
.main-layout__content {
Expand All @@ -82,8 +82,4 @@ export default defineComponent({
@apply flex flex-col h-full flex-1;
}
}
.main-layout__sidebar {
@include layout-sidebar;
}
</style>
22 changes: 22 additions & 0 deletions middleware/auth.global.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useNuxtApp, navigateTo } from "#app"

export default defineNuxtRouteMiddleware(async (to, from) => {

Check warning on line 3 in middleware/auth.global.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'from' is defined but never used. Allowed unused args must match /^_/u

Check failure on line 3 in middleware/auth.global.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Async arrow function has no 'await' expression

Check warning on line 3 in middleware/auth.global.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

'from' is defined but never used. Allowed unused args must match /^_/u

Check failure on line 3 in middleware/auth.global.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Async arrow function has no 'await' expression
const app = useNuxtApp()
const {localStorage} = window;

if (!app.$appSettings.auth.enabled) {
return;
}

// todo: move token to a store
if (to.name !== 'login' && !app.$authToken.token) {
return navigateTo('/login');

Check failure on line 13 in middleware/auth.global.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Async arrow function expected no return value

Check failure on line 13 in middleware/auth.global.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Async arrow function expected no return value
}

if (to.name === 'login' && to?.query?.token) {
localStorage?.setItem('token', to.query.token);
// todo: use store
app.$authToken.token = to.query.token;
return navigateTo('/');

Check failure on line 20 in middleware/auth.global.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Async arrow function expected no return value

Check failure on line 20 in middleware/auth.global.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Async arrow function expected no return value
}
})
3 changes: 3 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export default defineNuxtConfig({
],
},
},
plugins: [
'~/plugins/auth',
],
dir: {
static: 'static',
},
Expand Down
88 changes: 88 additions & 0 deletions pages/login.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<script setup lang="ts">
import { useNuxtApp, navigateTo } from "#app"

Check failure on line 2 in pages/login.vue

View workflow job for this annotation

GitHub Actions / build (18.x)

You cannot import layer "app" into "pages" (shared -> entities -> features -> widgets -> pages -> processes -> app)

Check failure on line 2 in pages/login.vue

View workflow job for this annotation

GitHub Actions / build (20.x)

You cannot import layer "app" into "pages" (shared -> entities -> features -> widgets -> pages -> processes -> app)
import { REST_API_URL } from "~/src/shared/lib/io";
import { IconSvg } from "~/src/shared/ui";
definePageMeta({

Check failure on line 6 in pages/login.vue

View workflow job for this annotation

GitHub Actions / build (18.x)

'definePageMeta' is not defined

Check failure on line 6 in pages/login.vue

View workflow job for this annotation

GitHub Actions / build (20.x)

'definePageMeta' is not defined
layout: 'blank'
})
const app = useNuxtApp()
const redirect = async () => {
await navigateTo(`${REST_API_URL}/${app.$appSettings.auth.login_url}`, {
external: true
})
}
</script>

<template>
<div class="login-page">
<div class="login-form-container">
<IconSvg class="login-form--logo" name="logo"/>
<div class="login-form">
<div class="login-form-left-block">
<h1 class="login-form--title">Welcome Back</h1>
<p class="pb-2 text-center text-sm text-gray-800">Let's get you signed in.</p>
<button class="login-form--button" @click="redirect">
<IconSvg class="w-6" name="lock" fill="currentcolor"/>
Continue to SSO
</button>
</div>
<div class="login-form-right-block"
style="background: url('/bg.jpg'); background-size: cover; background-position: center center;">
</div>
</div>
</div>
</div>
</template>


<style lang="scss" scoped>
@import "assets/mixins";
.login-page {
@apply bg-gray-800;
@apply h-screen w-screen;
}
.login-form-container {
@apply flex flex-col items-center justify-center flex-1;
@apply px-4 sm:px-0;
@apply h-full;
}
.login-form {
@apply flex w-full sm:w-3/4 md:w-2/3 xl:w-1/2 h-96;
@apply shadow-2xl;
@apply bg-gray-200;
@apply rounded-2xl;
@apply mt-10;
}
.login-form-left-block {
@apply flex flex-col flex-1 justify-center items-center;
@apply mb-8 p-12;
@apply w-1/2;
}
.login-form-right-block {
@apply w-0 md:w-1/2 h-full rounded-r-2xl;
}
.login-form--logo {
@apply w-48 text-gray-200;
}
.login-form--title {
@apply text-4xl text-center font-thin;
@apply my-10;
}
.login-form--button {
@apply bg-blue-500 hover:bg-blue-600 transition-colors;
@apply text-white rounded;
@apply px-4 py-2 gap-2;
@apply inline-flex;
}
</style>
42 changes: 42 additions & 0 deletions plugins/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useSettings } from "~/src/shared/lib/use-settings";

const {localStorage} = window;

// todo: use store for token
export default defineNuxtPlugin(async () => {
const {
api: {getSettings},
} = useSettings();

let settings = {
auth: {
enabled: false,
login_url: '/login',
},
version: '0.0.0',
}

try {
settings = await getSettings()
} catch (e) {
console.error('Server is not available!')
}

if (!settings.auth.enabled) {
return {
provide: {
authToken: {token: null},
appSettings: settings
}
}
}

const token: string | null = localStorage?.getItem('token')

return {
provide: {
authToken: {token},
appSettings: settings
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const toggleOpen = () => {
}
.sentry-exception-frame__head-title-dd {
@apply w-5 h-4 flex justify-center border border-purple-300 shadow bg-white dark:bg-gray-600 py-1 rounded transform rotate-180;
@apply w-5 h-4 flex justify-center shadow py-1 rounded transform rotate-180;
}
.sentry-exception-frame__head-title-dd--visible {
Expand Down
4 changes: 2 additions & 2 deletions src/entities/sentry/ui/sentry-exception/sentry-exception.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ const exceptionFrames = computed(() => {
const frames = props.exception.stacktrace.frames || [];
if (props.maxFrames > 0) {
return frames.reverse().slice(0, props.maxFrames);
return frames.slice(0, props.maxFrames);
}
return frames;
return [...frames].reverse();
});
</script>

Expand Down
4 changes: 2 additions & 2 deletions src/shared/lib/io/centrifuge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ class WSConnection {
return WSConnection.instance;
}

public getCentrifuge () {
public getCentrifuge() {
return this.centrifuge;
}
}


export const useCentrifuge: TUseCentrifuge = () => ({ centrifuge: WSConnection.getInstance().getCentrifuge() })
export const useCentrifuge: TUseCentrifuge = () => ({centrifuge: WSConnection.getInstance().getCentrifuge()})
35 changes: 27 additions & 8 deletions src/shared/lib/io/use-events-requests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { EventId, EventType , ServerEvent } from '../../types';
import type { EventId, EventType, ServerEvent } from '../../types';

Check failure on line 1 in src/shared/lib/io/use-events-requests.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

You cannot import layer "app" into "shared" (shared -> entities -> features -> widgets -> pages -> processes -> app)

Check failure on line 1 in src/shared/lib/io/use-events-requests.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

You cannot import layer "app" into "shared" (shared -> entities -> features -> widgets -> pages -> processes -> app)
import { REST_API_URL } from "./constants";
import { useNuxtApp } from "#app"

type TUseEventsRequests = () => {
getAll: () => Promise<ServerEvent<unknown>[]>,
Expand All @@ -11,23 +12,33 @@ type TUseEventsRequests = () => {
getEventRestUrl: (param: EventId | undefined) => string
}

// TODO: add 403 response handling

export const useEventsRequests: TUseEventsRequests = () => {
const getEventRestUrl = (param?: string) => `${REST_API_URL}/api/event${param ? `/${param}` : 's'}`
const app = useNuxtApp()
const token: string | null = app.$authToken.token
const headers = {"X-Auth-Token": token}
const getEventRestUrl = (param?: string): string => `${REST_API_URL}/api/event${param ? `/${param}` : 's'}`

const getAll = () => fetch(getEventRestUrl())
const getAll = () => fetch(getEventRestUrl(), {headers})
.then((response) => response.json())
.then((response) => {
if (response?.data) {
return response.data as ServerEvent<unknown>[]
}

if (response?.code === 403) {
console.error('Forbidden')
return [];
}

console.error('Fetch Error')

return [];
})
.then((events: ServerEvent<unknown>[]) => events)

const getSingle = (id: EventId) => fetch(getEventRestUrl(id))
const getSingle = (id: EventId) => fetch(getEventRestUrl(id), {headers})
.then((response) => response.json())
.then((response) => {
if (response?.data) {
Expand All @@ -36,22 +47,30 @@ export const useEventsRequests: TUseEventsRequests = () => {
return null;
})

const deleteSingle = (id: EventId) => fetch(getEventRestUrl(id), { method: 'DELETE' })
const deleteSingle = (id: EventId) => fetch(getEventRestUrl(id), {method: 'DELETE', headers})
.catch((err) => {
console.error('Fetch Error', err)
})

const deleteAll = () => fetch(getEventRestUrl(), { method: 'DELETE' })
const deleteAll = () => fetch(getEventRestUrl(), {method: 'DELETE', headers})
.catch((err) => {
console.error('Fetch Error', err)
})

const deleteList = (uuids: EventId[]) => fetch(getEventRestUrl(), { method: 'DELETE', body: JSON.stringify({ uuids }) })
const deleteList = (uuids: EventId[]) => fetch(getEventRestUrl(), {
method: 'DELETE',
headers,
body: JSON.stringify({uuids})
})
.catch((err) => {
console.error('Fetch Error', err)
})

const deleteByType = (type: EventType) => fetch(getEventRestUrl(), { method: 'DELETE', body: JSON.stringify({type}) })
const deleteByType = (type: EventType) => fetch(getEventRestUrl(), {
method: 'DELETE',
headers,
body: JSON.stringify({type})
})
.catch((err) => {
console.error('Fetch Error', err)
})
Expand Down
Loading

0 comments on commit 25b9782

Please sign in to comment.