Merge pull request #212 from bartvdbraak/unlighthouse-auth

Add Dockerfile for backend service and unlighthouse authentication
This commit is contained in:
Bart van der Braak 2024-02-19 12:40:28 +01:00 committed by GitHub
commit 3015ae0486
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 3087 additions and 166 deletions

View file

@ -74,14 +74,14 @@ jobs:
timeout: 360
- name: Install Dependencies
run: pnpm install -g @unlighthouse/cli puppeteer
run: pnpm install
- name: Run Unlighthouse
run: |
unlighthouse-ci \
--site "${{ github.ref == 'refs/heads/main' && env.WEBSITE_URL || steps.vercel_preview_url.outputs.preview_url }}" \
--reporter jsonExpanded \
--build-static
export SCAN_URL="${{ github.ref == 'refs/heads/main' && env.WEBSITE_URL || steps.vercel_preview_url.outputs.preview_url }}"
export AUTH_COOKIE="$(curl "https://$SCAN_URL/auth?/login" -H "Origin: https://$SCAN_URL" -F "email=test_user" -F "password=${{ secrets.TEST_USER_PASSWORD }}" --verbose 2>&1 | awk -F'pb_auth=' '/pb_auth/{print $2;exit}' | awk -F';' '{print $1}')"
pnpm run unlighthouse
- name: Upload report to Cloudflare pages
uses: cloudflare/wrangler-action@v3.4.1

1
.gitignore vendored
View file

@ -8,3 +8,4 @@ node_modules
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.unlighthouse

27
backend/Dockerfile Normal file
View file

@ -0,0 +1,27 @@
FROM alpine:3.19.1
RUN addgroup -S nonroot \
&& adduser -S nonroot -G nonroot
USER nonroot
ARG PB_VERSION=0.21.3
RUN apk add --no-cache \
unzip \
ca-certificates
# download and unzip PocketBase
ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip /tmp/pb.zip
RUN unzip /tmp/pb.zip -d /pb/
# uncomment to copy the local pb_migrations dir into the image
COPY ./pb_migrations /pb/pb_migrations
# uncomment to copy the local pb_hooks dir into the image
# COPY ./pb_hooks /pb/pb_hooks
EXPOSE 8080
# start PocketBase
CMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8080"]

View file

@ -9,7 +9,8 @@
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
"format": "prettier --write .",
"unlighthouse": "unlighthouse-ci"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
@ -33,6 +34,7 @@
"tailwindcss": "^3.3.6",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"unlighthouse": "^0.10.6",
"vite": "^5.0.3",
"zod": "^3.22.4"
},

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,9 @@
export { default as Metadata } from './metadata.svelte';
export { default as SiteFooter } from './site-footer.svelte';
export { default as UserNav } from './user-nav.svelte';
export { default as SiteNavBar } from './site-navbar.svelte';
export { default as TailwindIndicator } from './tailwind-indicator.svelte';
export { default as ModeToggle } from './mode-toggle.svelte';
export { default as Particles } from './particles.svelte';
export * from './icons';
export * from './nav';

View file

@ -1,2 +0,0 @@
export { default as MainNav } from './main-nav.svelte';
export { default as MobileNav } from './mobile-nav.svelte';

View file

@ -1,25 +0,0 @@
<script lang="ts">
import { page } from '$app/stores';
import { cn } from '$lib/utils';
import { navConfig } from '$lib/config/nav';
export let authenticated = false;
</script>
<div class="mr-4 hidden md:flex">
<nav class="flex items-center space-x-6 text-sm font-medium">
{#each navConfig.mainNav as navItem, index (navItem + index.toString())}
{#if navItem.href && (navItem.auth == authenticated || navItem.always)}
<a
href={navItem.href}
class={cn(
'transition-colors hover:text-foreground/80',
$page.url.pathname === navItem.href ? 'text-foreground' : 'text-foreground/60'
)}
>
{navItem.title}
</a>
{/if}
{/each}
</nav>
</div>

View file

@ -1,23 +0,0 @@
<script lang="ts">
import { page } from '$app/stores';
import { cn } from '$lib/utils';
export let href: string;
export let open: boolean;
let className: string | undefined | null = undefined;
export { className as class };
</script>
<a
{href}
on:click={() => (open = false)}
class={cn(
$page.url.pathname === href ? 'text-foreground' : 'text-foreground/60',
'hover:text-foreground',
className
)}
{...$$restProps}
>
<slot />
</a>

View file

@ -1,68 +0,0 @@
<script lang="ts">
import * as Sheet from '$lib/components/ui/sheet/';
import { HamburgerMenu } from 'radix-icons-svelte';
import { Button } from '$lib/components/ui/button';
import { navConfig } from '$lib/config/nav';
import { siteConfig } from '$lib/config/site';
import { Icons } from '../icons';
import MobileLink from './mobile-link.svelte';
let open = false;
export let authenticated = false;
</script>
<Sheet.Root bind:open>
<Sheet.Trigger asChild let:builder>
<Button
builders={[builder]}
variant="ghost"
class="mr-2 px-0 text-base hover:bg-transparent focus-visible:bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 md:hidden"
>
<HamburgerMenu class="h-5 w-5" />
<span class="sr-only">Toggle Menu</span>
</Button>
</Sheet.Trigger>
<Sheet.Content side="right" class="pr-0">
<MobileLink href="/" class="flex items-center" bind:open>
<span class="sr-only">Logo icon (return home)</span>
<div class="mr-4 rounded-sm bg-gray-950 p-0.5 dark:bg-transparent">
<Icons.logo />
</div>
<span class="font-mono font-bold tracking-tighter">{siteConfig.name}</span>
</MobileLink>
<div class="my-4 h-[calc(100vh-8rem)] overflow-auto pl-1 pt-10">
<div class="flex flex-col space-y-3">
{#each navConfig.mainNav as navItem, index (navItem + index.toString())}
{#if navItem.href && (navItem.auth == authenticated || navItem.always)}
<MobileLink href={navItem.href} bind:open class="pt-2 text-5xl font-bold">
{navItem.title}
</MobileLink>
{/if}
{/each}
</div>
<div class="flex flex-col space-y-2">
{#each navConfig.sidebarNav as navItem, index (index)}
<div class="flex flex-col space-y-3 pt-6">
<h4 class="font-medium">{navItem.title}</h4>
{#if navItem?.items?.length}
{#each navItem.items as item}
{#if !item.disabled && item.href}
<MobileLink href={item.href} bind:open class="text-muted-foreground">
{item.title}
{#if item.label}
<span
class="ml-2 rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs leading-none text-[#000000]"
>
{item.label}
</span>
{/if}
</MobileLink>
{/if}
{/each}
{/if}
</div>
{/each}
</div>
</div>
</Sheet.Content>
</Sheet.Root>

View file

@ -5,8 +5,10 @@
<footer class="container py-6">
<div class="space-y-1">
<p class="text-center text-sm text-muted-foreground">
&copy; {new Date().getFullYear()} &mdash; {siteConfig.name} by {siteConfig.author}. Licensed
under GPL-3.0.
&copy; {new Date().getFullYear()} &mdash;
<a href={siteConfig.links.gitHubProject} target="_blank">{siteConfig.name}</a>
by <a href={siteConfig.links.gitHubProfile} target="_blank">{siteConfig.author}</a>. Licensed
GPL-3.0.
</p>
</div>
</footer>

View file

@ -1,7 +1,6 @@
<script lang="ts">
import { Icons, ModeToggle, MainNav, MobileNav } from '$lib/components/site';
import { Icons, ModeToggle, UserNav } from '$lib/components/site';
import { siteConfig } from '$lib/config/site';
import UserNav from './nav/user-nav.svelte';
export let authenticated = false;
export let user: object | null = null;
@ -18,11 +17,11 @@
</div>
<span class="text-xl font-bold tracking-tight">{siteConfig.name}</span>
</a>
<MainNav {authenticated} />
<div class="flex flex-1 items-center justify-end space-x-2 sm:space-x-4">
<ModeToggle />
{#if !authenticated}
<ModeToggle />
{/if}
<UserNav {authenticated} {user} />
<MobileNav {authenticated} />
</div>
</div>
</header>

View file

@ -26,7 +26,7 @@
</div>
</DropdownMenu.Label>
<DropdownMenu.Separator />
<DropdownMenu.Item>Dashboards</DropdownMenu.Item>
<DropdownMenu.Item href="/dashboard">Dashboards</DropdownMenu.Item>
<DropdownMenu.Item>Connectors</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Label class="text-xs leading-none text-muted-foreground">

View file

@ -1,17 +0,0 @@
import type { NavItem, SidebarNavItem } from '$lib/types/nav';
interface NavConfig {
mainNav: NavItem[];
sidebarNav: SidebarNavItem[];
}
export const navConfig: NavConfig = {
mainNav: [
{
title: 'Dashboard',
href: '/dashboard',
auth: true
}
],
sidebarNav: []
};

View file

@ -1,4 +1,5 @@
<script lang="ts">
import { browser } from '$app/environment';
import { enhance } from '$app/forms';
import { Icons } from '$lib/components/site/icons';
import { Button } from '$lib/components/ui/button';
@ -40,11 +41,17 @@
console.error(err);
}
}
let tab: string = 'login';
if (browser) {
const urlSearchParams = new URLSearchParams(window.location.search);
tab = urlSearchParams.get('tab') || 'login';
}
</script>
<div class="lg:p-8">
<Tabs.Root
value={form?.showLogin ? 'login' : undefined}
value={form?.showLogin ? 'login' : tab}
class="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]"
>
<Tabs.List class="grid w-full grid-cols-2">
@ -74,7 +81,7 @@
<div class="grid gap-2">
<Label for="email">Email or username</Label>
<Input
id="email"
id="email-login"
name="email"
type="email"
autocapitalize="none"
@ -85,7 +92,7 @@
</div>
<div class="grid gap-2">
<Label for="password">Password</Label>
<Input id="password" name="password" type="password" disabled={isLoading} />
<Input id="password-login" name="password" type="password" disabled={isLoading} />
</div>
<Button type="submit" disabled={isLoading}>
{#if isLoading}
@ -131,7 +138,7 @@
<div class="grid gap-2">
<Label for="email">Email</Label>
<Input
id="email"
id="email-register"
name="email"
type="email"
autocapitalize="none"
@ -142,11 +149,16 @@
</div>
<div class="grid gap-2">
<Label for="password">Password</Label>
<Input id="password" name="password" type="password" disabled={isLoading} />
<Input id="password-register" name="password" type="password" disabled={isLoading} />
</div>
<div class="grid gap-2">
<Label for="password">Confirm password</Label>
<Input id="password" name="passwordConfirm" type="password" disabled={isLoading} />
<Input
id="confirm-password-register"
name="passwordConfirm"
type="password"
disabled={isLoading}
/>
</div>
<Button type="submit" disabled={isLoading}>
{#if isLoading}
@ -165,6 +177,11 @@
</form>
</div>
</Tabs.Content>
<p class="px-8 text-center text-xs text-muted-foreground">
Don't have an account? <a class="text-primary underline" href="/auth?tab=register">Register</a
>.<br />
Forgot password? <a class="text-primary underline" href="/reset-password">Reset password.</a>
</p>
{#if providers.length}
<form
method="POST"
@ -252,9 +269,4 @@
</form>
{/if}
</Tabs.Root>
<p class="px-8 py-2 text-center text-xs text-muted-foreground">
Don't have an account? <a class="text-primary underline" href="/register">Sign up.</a> <br />
Forgot password? <a class="text-primary underline" href="/reset-password">Reset password.</a>
</p>
</div>

18
unlighthouse.config.ts Normal file
View file

@ -0,0 +1,18 @@
import { defineConfig } from 'unlighthouse';
export default defineConfig({
site: process.env.SCAN_URL || 'http://localhost:5173/',
cookies: [
{
name: 'pb_auth',
value: process.env.AUTH_COOKIE || '',
domain: process.env.SCAN_URL || 'http://localhost:5173/',
path: '/',
sameSite: 'Lax'
}
],
ci: {
reporter: 'jsonExpanded',
buildStatic: true
}
});