uhh stuff
This commit is contained in:
parent
29807d104c
commit
237b1dd368
15 changed files with 243 additions and 36 deletions
|
@ -31,6 +31,7 @@
|
||||||
"prettier-plugin-svelte": "^2.7.0",
|
"prettier-plugin-svelte": "^2.7.0",
|
||||||
"svelte": "^3.44.0",
|
"svelte": "^3.44.0",
|
||||||
"svelte-check": "^2.7.1",
|
"svelte-check": "^2.7.1",
|
||||||
|
"svelte-feather-icons": "^4.0.0",
|
||||||
"svelte-preprocess": "^4.10.7",
|
"svelte-preprocess": "^4.10.7",
|
||||||
"tailwindcss": "^3.1.5",
|
"tailwindcss": "^3.1.5",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
|
|
|
@ -2,3 +2,8 @@
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
:root,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
|
import { AlertCircleIcon, CheckCircleIcon } from 'svelte-feather-icons';
|
||||||
|
|
||||||
import type { UiContainer, UiNodeInputAttributesTypeEnum } from '@ory/client';
|
import type { UiContainer, UiNodeInputAttributesTypeEnum } from '@ory/client';
|
||||||
import {
|
import {
|
||||||
|
@ -19,36 +20,21 @@
|
||||||
{#if message.type == 'info'}
|
{#if message.type == 'info'}
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
<div>
|
<div>
|
||||||
<svg
|
<AlertCircleIcon class="stroke-current flex-shrink-0 w-6 h-6" />
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
class="stroke-current flex-shrink-0 w-6 h-6"
|
|
||||||
><path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
<span>{message.text}</span>
|
<span>{message.text}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else if message.type == 'error'}
|
{:else if message.type == 'error'}
|
||||||
<div class="alert alert-error">
|
<div class="alert alert-error">
|
||||||
<div>
|
<div>
|
||||||
<svg
|
<AlertCircleIcon class="stroke-current flex-shrink-0 w-6 h-6" />
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<span>{message.text}</span>
|
||||||
class="stroke-current flex-shrink-0 h-6 w-6"
|
</div>
|
||||||
fill="none"
|
</div>
|
||||||
viewBox="0 0 24 24"
|
{:else if message.type == 'success'}
|
||||||
><path
|
<div class="alert alert-success">
|
||||||
stroke-linecap="round"
|
<div>
|
||||||
stroke-linejoin="round"
|
<CheckCircleIcon class="stroke-current flex-shrink-0 w-6 h-6" />
|
||||||
stroke-width="2"
|
|
||||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
<span>{message.text}</span>
|
<span>{message.text}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -123,7 +109,6 @@
|
||||||
{:else if node.attributes.type == 'hidden'}
|
{:else if node.attributes.type == 'hidden'}
|
||||||
<input
|
<input
|
||||||
on:click={eval(node.attributes.onclick ?? '')}
|
on:click={eval(node.attributes.onclick ?? '')}
|
||||||
class="checkbox"
|
|
||||||
autocomplete={node.attributes.autocomplete}
|
autocomplete={node.attributes.autocomplete}
|
||||||
disabled={node.attributes.disabled}
|
disabled={node.attributes.disabled}
|
||||||
name={node.attributes.name}
|
name={node.attributes.name}
|
||||||
|
|
23
src/routes/+layout.server.ts
Normal file
23
src/routes/+layout.server.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import type { LayoutServerLoad } from './$types';
|
||||||
|
import { KratosPublicApi } from '$lib/server/APIClients.js';
|
||||||
|
|
||||||
|
export const load: LayoutServerLoad = async ({ request }) => {
|
||||||
|
try {
|
||||||
|
const current_user = await KratosPublicApi.toSession(
|
||||||
|
undefined,
|
||||||
|
request.headers.get('Cookie') ?? undefined
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
logged_in: true,
|
||||||
|
logout_url: (
|
||||||
|
await KratosPublicApi.createSelfServiceLogoutFlowUrlForBrowsers(
|
||||||
|
request.headers.get('Cookie') ?? undefined
|
||||||
|
)
|
||||||
|
).data.logout_url
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
logged_in: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,6 +1,48 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { MenuIcon } from 'svelte-feather-icons';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
export let data: PageData;
|
||||||
|
|
||||||
import '../app.postcss';
|
import '../app.postcss';
|
||||||
import '../app.postcss';
|
import '../app.postcss';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="navbar bg-base-100 fixed h-16 z-10">
|
||||||
|
<div class="navbar-start">
|
||||||
|
<div class="dropdown">
|
||||||
|
<button tabindex="0" class="btn btn-ghost lg:hidden">
|
||||||
|
<MenuIcon class="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
<ul
|
||||||
|
tabindex="0"
|
||||||
|
class="menu menu-compact dropdown-content mt-3 p-2 shadow bg-base-100 rounded-box w-52"
|
||||||
|
role="menu"
|
||||||
|
>
|
||||||
|
{#if data.logged_in}
|
||||||
|
<li><a href="/settings">Account Settings</a></li>
|
||||||
|
<li><a href="/verification">Email Verification</a></li>
|
||||||
|
<li><a href={data.logout_url}>Log Out</a></li>
|
||||||
|
{:else}
|
||||||
|
<li><a href="/login">Log In</a></li>
|
||||||
|
<li><a href="/registration">Sign Up</a></li>
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-ghost normal-case text-xl" href="/">ørkesløs</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-end hidden lg:flex">
|
||||||
|
<ul class="menu menu-horizontal p-0">
|
||||||
|
{#if data.logged_in}
|
||||||
|
<li><a href="/settings">Account Settings</a></li>
|
||||||
|
<li><a href="/verification">Email Verification</a></li>
|
||||||
|
<li><a href={data.logout_url}>Log Out</a></li>
|
||||||
|
{:else}
|
||||||
|
<li><a href="/login">Log In</a></li>
|
||||||
|
<li><a href="/registration">Sign Up</a></li>
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pt-16 h-full">
|
||||||
<slot />
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen justify-center bg-base-100">
|
<div class="flex h-full justify-center bg-base-100">
|
||||||
<ul class="place-self-center menu max-w-sm p-3 rounded-box shadow-xl bg-base-200 text-lg">
|
<ul class="place-self-center menu max-w-sm p-3 rounded-box shadow-xl bg-base-200 text-lg">
|
||||||
{#if data.logged_in}
|
{#if data.logged_in}
|
||||||
<li class="menu-title">
|
<li class="menu-title">
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
<li><a href={data.logout_url}>Log Out</a></li>
|
<li><a href={data.logout_url}>Log Out</a></li>
|
||||||
{:else}
|
{:else}
|
||||||
<li><a href="/login">Log In</a></li>
|
<li><a href="/login">Log In</a></li>
|
||||||
<li><a href="/signup">Sign Up</a></li>
|
<li><a href="/registration">Sign Up</a></li>
|
||||||
{/if}
|
{/if}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen justify-center">
|
<div class="flex h-full justify-center">
|
||||||
<form method="POST" class="place-self-center form-control space-y-2 max-w-sm">
|
<form method="POST" class="place-self-center form-control space-y-2 max-w-sm">
|
||||||
<div>
|
<div>
|
||||||
Hello {data.username}!
|
Hello {data.username}!
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen justify-center">
|
<div class="flex h-full justify-center">
|
||||||
<div class="place-self-center space-y-2 max-w-sm">
|
<div class="place-self-center space-y-2 max-w-sm">
|
||||||
<h1 class="text-lg font-bold">{data.title}</h1>
|
<h1 class="text-lg font-bold">{data.title}</h1>
|
||||||
{#if data.subtitle}
|
{#if data.subtitle}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen justify-center">
|
<div class="flex h-full justify-center">
|
||||||
<form method="POST" class="place-self-center form-control space-y-2 max-w-sm">
|
<form method="POST" class="place-self-center form-control space-y-2 max-w-sm">
|
||||||
<div>
|
<div>
|
||||||
Hello {data.username}!
|
Hello {data.username}!
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen justify-center">
|
<div class="flex h-full justify-center">
|
||||||
<div
|
<div
|
||||||
action={data.flow.ui.action}
|
action={data.flow.ui.action}
|
||||||
method={data.flow.ui.method}
|
method={data.flow.ui.method}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen justify-center">
|
<div class="flex h-full justify-center">
|
||||||
<div class="place-self-center space-y-2 max-w-sm">
|
<div class="place-self-center space-y-2 max-w-sm">
|
||||||
<h1 class="text-lg font-bold">{data.title}</h1>
|
<h1 class="text-lg font-bold">{data.title}</h1>
|
||||||
{#if data.subtitle}
|
{#if data.subtitle}
|
||||||
|
|
57
src/routes/settings/+page.server.ts
Normal file
57
src/routes/settings/+page.server.ts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
|
import { KratosAdminApi, KratosPublicApi } from '$lib/server/APIClients.js';
|
||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import { KRATOS_PUBLIC_URL } from '$lib/server/config';
|
||||||
|
import type { SelfServiceLoginFlow, SelfServiceSettingsFlow } from '@ory/client';
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ url, request }) => {
|
||||||
|
const flow = url.searchParams.get('flow');
|
||||||
|
const return_to = url.searchParams.get('return_to') ?? '';
|
||||||
|
|
||||||
|
const initFlowUrl = `${KRATOS_PUBLIC_URL.replace(
|
||||||
|
/\/$/,
|
||||||
|
''
|
||||||
|
)}/self-service/settings/browser?${new URLSearchParams({
|
||||||
|
return_to: return_to.toString()
|
||||||
|
}).toString()}`;
|
||||||
|
if (flow == undefined) {
|
||||||
|
throw redirect(303, initFlowUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: session } = await KratosPublicApi.toSession(
|
||||||
|
undefined,
|
||||||
|
request.headers.get('Cookie') ?? undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
const logoutUrl =
|
||||||
|
(
|
||||||
|
await KratosAdminApi.createSelfServiceLogoutFlowUrlForBrowsers(
|
||||||
|
request.headers.get('Cookie') ?? undefined
|
||||||
|
).catch(() => ({ data: { logout_url: '' } }))
|
||||||
|
).data.logout_url || '';
|
||||||
|
|
||||||
|
const identityCredentialTrait =
|
||||||
|
session.identity.traits.username || session.identity.traits.email || '';
|
||||||
|
|
||||||
|
const sessionText =
|
||||||
|
identityCredentialTrait !== ''
|
||||||
|
? `You are currently logged in as ${identityCredentialTrait} `
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const { data: settings_flow }: { data: SelfServiceSettingsFlow } =
|
||||||
|
await KratosPublicApi.getSelfServiceSettingsFlow(
|
||||||
|
flow,
|
||||||
|
undefined,
|
||||||
|
request.headers.get('Cookie') ?? undefined
|
||||||
|
).catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
throw redirect(303, initFlowUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
KRATOS_PUBLIC_URL: KRATOS_PUBLIC_URL,
|
||||||
|
flow: settings_flow,
|
||||||
|
sessionText: sessionText,
|
||||||
|
logoutURL: logoutUrl
|
||||||
|
};
|
||||||
|
};
|
87
src/routes/settings/+page.svelte
Normal file
87
src/routes/settings/+page.svelte
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import KratosForm from '$lib/KratosForm.svelte';
|
||||||
|
import { filterNodesByGroups } from '@ory/integrations/ui';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
export let data: PageData;
|
||||||
|
|
||||||
|
export let profile_ui = {
|
||||||
|
...data.flow.ui,
|
||||||
|
nodes: filterNodesByGroups({
|
||||||
|
nodes: data.flow.ui.nodes,
|
||||||
|
groups: 'profile'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export let password_ui = {
|
||||||
|
...data.flow.ui,
|
||||||
|
nodes: filterNodesByGroups({
|
||||||
|
nodes: data.flow.ui.nodes,
|
||||||
|
groups: 'password'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export let oidc_ui = {
|
||||||
|
...data.flow.ui,
|
||||||
|
nodes: filterNodesByGroups({
|
||||||
|
nodes: data.flow.ui.nodes,
|
||||||
|
groups: 'oidc'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export let lookup_secret_ui = {
|
||||||
|
...data.flow.ui,
|
||||||
|
nodes: filterNodesByGroups({
|
||||||
|
nodes: data.flow.ui.nodes,
|
||||||
|
groups: 'lookup_secret'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export let webauthn_ui = {
|
||||||
|
...data.flow.ui,
|
||||||
|
nodes: filterNodesByGroups({
|
||||||
|
nodes: data.flow.ui.nodes,
|
||||||
|
groups: 'webauthn'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export let totp_ui = {
|
||||||
|
...data.flow.ui,
|
||||||
|
nodes: filterNodesByGroups({
|
||||||
|
nodes: data.flow.ui.nodes,
|
||||||
|
groups: 'totp'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let tabs = [
|
||||||
|
{ name: 'Profile', ui: profile_ui },
|
||||||
|
{ name: 'Password', ui: password_ui },
|
||||||
|
{ name: 'OpenID', ui: oidc_ui },
|
||||||
|
{ name: 'Recovery Codes', ui: lookup_secret_ui },
|
||||||
|
{ name: 'Security Keys', ui: webauthn_ui },
|
||||||
|
{ name: 'Authenticator Apps', ui: totp_ui }
|
||||||
|
].filter((e) => {
|
||||||
|
return e.ui.nodes.filter((node) => node.group != 'default').length != 0;
|
||||||
|
});
|
||||||
|
let activeTab = 0;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex h-full justify-center">
|
||||||
|
<div class="place-self-center space-y-2 max-w-xl">
|
||||||
|
<h1 class="text-lg font-bold">Account Settings</h1>
|
||||||
|
{data.sessionText}
|
||||||
|
<div class="tabs">
|
||||||
|
{#each tabs as tab, index}
|
||||||
|
<button
|
||||||
|
class="tab tab-bordered"
|
||||||
|
class:tab-active={activeTab == index}
|
||||||
|
on:click={() => (activeTab = index)}>{tab.name}</button
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{#each tabs as tab, index}
|
||||||
|
<div class="card" class:hidden={activeTab != index}>
|
||||||
|
<KratosForm ui={tab.ui} />
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -4,7 +4,7 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen justify-center">
|
<div class="flex h-full justify-center">
|
||||||
<div class="place-self-center space-y-2 max-w-sm">
|
<div class="place-self-center space-y-2 max-w-sm">
|
||||||
<h1 class="text-lg font-bold">Verify Account</h1>
|
<h1 class="text-lg font-bold">Verify Account</h1>
|
||||||
<KratosForm ui={data.flow.ui} />
|
<KratosForm ui={data.flow.ui} />
|
||||||
|
|
|
@ -2347,6 +2347,13 @@ svelte-check@^2.7.1:
|
||||||
svelte-preprocess "^4.0.0"
|
svelte-preprocess "^4.0.0"
|
||||||
typescript "*"
|
typescript "*"
|
||||||
|
|
||||||
|
svelte-feather-icons@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte-feather-icons/-/svelte-feather-icons-4.0.0.tgz#fdffcce3a81782008f7e621cb37a29d041630aef"
|
||||||
|
integrity sha512-4ieUsjp+VYa1r6y80jDt9zRiRUZyJNbESpRdHdJJhiBubyuXX96A7f1UZSK4olxzP6Qsg5ZAuyZlnmvD+/swAA==
|
||||||
|
dependencies:
|
||||||
|
svelte "^3.38.2"
|
||||||
|
|
||||||
svelte-hmr@^0.15.1:
|
svelte-hmr@^0.15.1:
|
||||||
version "0.15.1"
|
version "0.15.1"
|
||||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.15.1.tgz#d11d878a0bbb12ec1cba030f580cd2049f4ec86b"
|
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.15.1.tgz#d11d878a0bbb12ec1cba030f580cd2049f4ec86b"
|
||||||
|
@ -2376,7 +2383,7 @@ svelte-preprocess@^4.0.0, svelte-preprocess@^4.10.7:
|
||||||
sorcery "^0.10.0"
|
sorcery "^0.10.0"
|
||||||
strip-indent "^3.0.0"
|
strip-indent "^3.0.0"
|
||||||
|
|
||||||
svelte@^3.44.0:
|
svelte@^3.38.2, svelte@^3.44.0:
|
||||||
version "3.53.1"
|
version "3.53.1"
|
||||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.53.1.tgz#db9d7df7a8f570e8e22547444c149208b1914442"
|
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.53.1.tgz#db9d7df7a8f570e8e22547444c149208b1914442"
|
||||||
integrity sha512-Q4/hHkktZogGhN5iqxqSi9sjEVoe/NbIxX4hXEHoasTxj+TxEQVAq66LnDMdAZxjmsodkoI5F3slqsS68U7FNw==
|
integrity sha512-Q4/hHkktZogGhN5iqxqSi9sjEVoe/NbIxX4hXEHoasTxj+TxEQVAq66LnDMdAZxjmsodkoI5F3slqsS68U7FNw==
|
||||||
|
|
Loading…
Reference in a new issue