Skip to content

Commit

Permalink
Add local auth support
Browse files Browse the repository at this point in the history
  • Loading branch information
yunusefendi52 committed Dec 3, 2024
1 parent 73a5dbf commit 75bac72
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 47 deletions.
14 changes: 1 addition & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,7 @@ Still in development, see roadmap

#### Ensure you have the required .env

```bash
NUXT_DB_URL=
NUXT_DB_AUTH_TOKEN=
NUXT_S3_ENDPOINT=
NUXT_S3_ACCESS_KEY_ID=
NUXT_S3_SECRET_ACCESS_KEY=
NUXT_JWT_KEY=
NUXT_SIGNIN_KEY=
NUXT_GOOGLE_CLIENT_ID=
NUXT_GOOGLE_CLIENT_SECRET=
NUXT_ADMIN_KEY_KEY=
NUXT_PUBLIC_ADMIN_KEY_ENABLE=
```
See `docker-compose.env` in the repo

#### Make sure to install the dependencies:

Expand Down
19 changes: 14 additions & 5 deletions assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@
@tailwind utilities;
}

html,
body {
--p-content-border-color: var(--p-surface-200);
}

.appdark html,
.appdark body {
--p-content-border-color: var(--p-surface-800);
}

html,
body {
--p-datatable-header-cell-background: transparent;
Expand All @@ -19,7 +29,6 @@ body {
font-size: 15px;

--p-tabmenu-active-bar-height: 2.5px;
--p-content-border-color: var(--p-datatable-border-color);
--p-tabmenu-item-color: var(--p-text-color);

word-break: break-word;
Expand All @@ -30,7 +39,7 @@ body {
}

.p-datatable-table-container {
border: 1px var(--p-datatable-border-color) solid;
border: 1px var(--p-content-border-color) solid;
border-radius: var(--p-border-radius-md);
}

Expand All @@ -43,7 +52,7 @@ body {
}

.p-divider-vertical.divider-app::before {
border-left: 1px solid var(--p-datatable-border-color);
border-left: 1px solid var(--p-content-border-color);
left: unset !important;
}

Expand All @@ -52,7 +61,7 @@ body {
}

.p-divider-horizontal.divider-app::before {
border-top: 1px solid var(--p-datatable-border-color);
border-top: 1px solid var(--p-content-border-color);
left: unset !important;
}

Expand All @@ -61,7 +70,7 @@ body {
}

.card {
border: 1px var(--p-datatable-border-color) solid;
border: 1px var(--p-content-border-color) solid;
border-radius: var(--p-border-radius-md);
padding: 15px;
}
Expand Down
2 changes: 1 addition & 1 deletion components/AppDivider.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div :class="orientation === 'vertical' ? 'h-full' : 'w-full'" style="background: var(--p-datatable-border-color);"
<div :class="orientation === 'vertical' ? 'h-full' : 'w-full'" style="background: var(--p-content-border-color);"
:style="{
height: orientation === 'vertical' ? null : '1px',
width: orientation === 'vertical' ? '1px' : null,
Expand Down
2 changes: 1 addition & 1 deletion components/ManageAppTester.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<AppCard class="flex flex-col gap-1 justify-stretch !p-2">
<form @submit.prevent="mutate">
<div class="flex flex-row gap-2">
<InputText class="flex-1" name="email" placeholder="Email" type="email" size="small" />
<InputText class="flex-1" name="email" placeholder="Email" size="small" />
<Button label="Create Invitation" size="small" :loading="isPending" type="submit" />
</div>
<div class="flex flex-row gap-2 mt-2 items-center" v-if="data">
Expand Down
26 changes: 14 additions & 12 deletions docker-compose.env
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
# Generate key using openssl rand -base64 32

NUXT_ADMIN_KEY_KEY=72st2uxZ8N9RJwCKPu+I3eTua6GHh09eRbKsmrZRqks=
NUXT_PUBLIC_ADMIN_KEY_ENABLE=true
NUXT_APP_ENABLE_DRIZZLE_LOGGING=false
NUXT_DB_URL=http://db:8080
# Change to your own ip/domain address for S3 server
NUXT_S3_ENDPOINT=http://192.168.100.119:9000
NUXT_S3_ACCESS_KEY_ID=7ebd63b0d9bb4218a837901ca0e571d4
NUXT_S3_SECRET_ACCESS_KEY=7ebd63b0d9bb4218a837901ca0e571d4
NUXT_JWT_KEY=5zRhfi/Aej8xhof7idF1uHPded9BpPeCkvEIZDHbnA0=
NUXT_SIGNIN_KEY=vfJcr5Ian4xSYVm0k6qFOEJieZdfE6HXawEpr4bN/qI=
NUXT_GOOGLE_CLIENT_ID=
NUXT_GOOGLE_CLIENT_SECRET=
NUXT_LOCAL_AUTHS=yunus1=a168746dc0bc427b9aac07a0c40c2efc;yunus2=d920d57cc4684580bee7f8db3a29e57c
NUXT_PUBLIC_LOCAL_AUTH_ENABLED=true
NUXT_APP_ENABLE_DRIZZLE_LOGGING=true
NUXT_DB_URL=libsql://libsql.turso.io
NUXT_DB_AUTH_TOKEN=
NUXT_S3_ENDPOINT=https://s3endpoint
NUXT_S3_ACCESS_KEY_ID=cd28e489b9a94daa893fa77b81fe82d4
NUXT_S3_SECRET_ACCESS_KEY=f98f62c0535f43ce954ad23e3a4c7a69
NUXT_JWT_KEY=36b3a2590d734b4aaf31bca4484647f6
NUXT_SIGNIN_KEY=a9a9e44d5344448789813e3ca7014d0e
NUXT_PUBLIC_GOOGLE_CLIENT_ID=
NUXT_APP_MIGRATION_ENABLE=true
NUXT_APP_MIGRATION_DIR=
NUXT_APP_CREATE_S3BUCKET=true
NUXT_APP_API_AUTH_KEY=KJLZ5VrAPFs2jif6Mx15wuzILBwvZTVJ6Wis6bVs2iA=
2 changes: 1 addition & 1 deletion layouts/auth-layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
<div class="flex items-center justify-center h-full w-full">
<slot />
</div>
</template>
</template>
8 changes: 2 additions & 6 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,16 @@ export default defineNuxtConfig({
limitUploadSizeMb: 120,
apiAuthKey: '',
},
LOCAL_AUTHS: '',
JWT_KEY: '',
DB_URL: '',
DB_AUTH_TOKEN: '',
S3_ENDPOINT: '',
S3_ACCESS_KEY_ID: '',
S3_SECRET_ACCESS_KEY: '',
adminKey: {
key: '' // generate using openssl
},
public: {
GOOGLE_CLIENT_ID: '',
adminKey: {
enable: true,
},
LOCAL_AUTH_ENABLED: false,
},
},

Expand Down
38 changes: 34 additions & 4 deletions pages/signin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
<AppIcon class="h-12 fill-black dark:fill-white" />
<span class="text-3xl font-semibold text-center">DistApp</span>
</div>
<form class="w-full flex flex-col gap-3" v-if="LOCAL_AUTH_ENABLED" @submit.prevent="(e) => signInAuth(e)">
<InputText required name="username" placeholder="Username" fluid />
<InputText required name="password" placeholder="Password" type="password" fluid />
<Button type="submit" label="Sign In" :loading="isPending" />
</form>
<AppDivider :orientation="'horizontal'" v-if="LOCAL_AUTH_ENABLED" />
<div class="w-full flex justify-center" style="color-scheme: auto;">
<GoogleSignInButton @success="handleLoginSuccess" @error="handleLoginError"></GoogleSignInButton>
</div>
Expand All @@ -19,17 +25,21 @@ import {
type CredentialResponse,
} from "vue3-google-signin";
function handleSuccessSignIn(r: { param: string } | undefined) {
if (r) {
location.href = `/?${r.param}`
}
}
const handleLoginSuccess = async (response: CredentialResponse) => {
const r = await $fetch('/api/auth/sign-in-google', {
method: 'post',
body: {
token: response.credential,
},
})
if (r) {
location.href = `/?${r.param}`
}
};
handleSuccessSignIn(r)
}
const handleLoginError = () => {
console.error("Login failed");
Expand All @@ -51,6 +61,26 @@ if (!isAddAccount.value) {
})
}
}
const { public: { LOCAL_AUTH_ENABLED } } = useRuntimeConfig()
const { mutate: signInAuth, isPending } = useMutation({
mutationFn: async (r: any) => {
if (!LOCAL_AUTH_ENABLED) {
return
}
const request = getObjectForm(r)
await $fetch.raw('/api/auth/sign-in-auth', {
method: 'post',
body: request,
}).then(e => {
if (e.ok) {
handleSuccessSignIn(e._data)
}
})
},
})
</script>

<style scoped>
Expand Down
2 changes: 1 addition & 1 deletion server/api/apps/testers/create-invitation-tester.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default defineEventHandler(async (event) => {
orgName: z.string().max(128),
appName: z.string().max(128),
groupName: z.string().max(128),
email: z.string().email(),
email: z.string().min(1).max(128),
}).parse)
email = email.trim()

Expand Down
40 changes: 40 additions & 0 deletions server/api/auth/sign-in-auth.post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { isNull } from "drizzle-orm"
import type { EventHandlerRequest, H3Event } from "h3"
import * as jose from 'jose'
import { generateUserToken, signInUser } from "./sign-in-google.post"

const alg = 'HS256'

export default defineEventHandler(async event => {
const { username, password } = await readValidatedBody(event, z.object({
username: z.string().min(1),
password: z.string().min(1),
}).parse)
const localAuths = getLocalAuths(useRuntimeConfig(event).LOCAL_AUTHS)
const localAuthed = localAuths.find(e => e.username === username && e.password === password)
if (!localAuthed) {
throw createError({
message: 'Invalid local auth',
statusCode: 400,
})
}
const { token: userToken } = await generateUserToken(event, 'localauth', localAuthed.username, localAuthed.username, localAuthed.username)
signInUser(event, userToken)
const param = new URLSearchParams({
usr: userToken,
e: localAuthed.username,
})
return {
param: param.toString(),
}
})

export function getLocalAuths(localAuths: string): { username: string, password: string }[] {
return localAuths.split(';').map(e => {
const s = e.split('=')
return {
username: s[0],
password: s[1],
}
})
}
2 changes: 1 addition & 1 deletion server/api/auth/sign-in-google.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default defineEventHandler(async event => {
}
})

const generateUserToken = async (
export const generateUserToken = async (
event: H3Event<EventHandlerRequest>,
signInProvider: string,
userId: string,
Expand Down
2 changes: 1 addition & 1 deletion server/api/invitations/create-invite-link.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { generateTokenWithOptions } from "~/server/utils/token-utils"
export default defineEventHandler(async (event) => {
var { orgName, email } = await readValidatedBody(event, z.object({
orgName: z.string().max(128),
email: z.string().email(),
email: z.string().min(1).max(128),
}).parse)
email = email.trim()
if (!email) {
Expand Down
2 changes: 1 addition & 1 deletion server/api/org-people/change-role.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export default defineEventHandler(async (event) => {
const currentUserId = event.context.auth.userId
const { roleId, email, orgName } = await readValidatedBody(event, z.object({
roleId: z.enum(["admin", "collaborator"]),
email: z.string().email(),
email: z.string().min(1).max(128),
orgName: z.string().trim().min(1),
}).parse)

Expand Down

0 comments on commit 75bac72

Please sign in to comment.