Compare commits
3 Commits
0816cbe9e5
...
7dd52d8890
Author | SHA1 | Date | |
---|---|---|---|
7dd52d8890 | |||
70e640aa9a | |||
ffa4496c16 |
4
src/app.d.ts
vendored
4
src/app.d.ts
vendored
@ -1,9 +1,5 @@
|
|||||||
// See https://kit.svelte.dev/docs/types#app
|
// See https://kit.svelte.dev/docs/types#app
|
||||||
// for information about these interfaces
|
// for information about these interfaces
|
||||||
declare module '@fortawesome/pro-solid-svg-icons/index.es' {
|
|
||||||
export * from '@fortawesome/pro-solid-svg-icons';
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace App {
|
namespace App {
|
||||||
// interface Error {}
|
// interface Error {}
|
||||||
|
28
src/hooks.server.ts
Normal file
28
src/hooks.server.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { authenticateUser } from "$lib/js/authenticate"
|
||||||
|
import type { Handle } from "@sveltejs/kit"
|
||||||
|
import { redirect } from "@sveltejs/kit"
|
||||||
|
import { error } from "@sveltejs/kit"
|
||||||
|
|
||||||
|
export const handle : Handle = async({event, resolve}) => {
|
||||||
|
event.locals.user = await authenticateUser(event.cookies)
|
||||||
|
if(event.url.pathname.startsWith('/rezepte/edit') || event.url.pathname.startsWith('/rezepte/add')){
|
||||||
|
if(!event.locals.user){
|
||||||
|
throw redirect(303, "/login")
|
||||||
|
}
|
||||||
|
else if(!event.locals.user.access.includes("rezepte")){
|
||||||
|
throw error(401, "Your user does not have access to this page")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(event.url.pathname.startsWith('/abrechnung')){
|
||||||
|
console.log(event.locals.user)
|
||||||
|
if(!event.locals.user){
|
||||||
|
throw redirect(303, "/login")
|
||||||
|
}
|
||||||
|
else if(!event.locals.user.access.includes("abrechnung")){
|
||||||
|
throw error(401, "Your User does not have access to this page")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await resolve(event)
|
||||||
|
return response
|
||||||
|
}
|
@ -111,9 +111,6 @@ export function edit_ingredient_and_close_modal(){
|
|||||||
modal_el.close();
|
modal_el.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function show_keys(event){
|
|
||||||
console.log(event.ctrlKey, event.key)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -122,7 +122,6 @@
|
|||||||
const item = await res.json();
|
const item = await res.json();
|
||||||
}
|
}
|
||||||
async function doAdd () {
|
async function doAdd () {
|
||||||
console.log(add_info.total_time)
|
|
||||||
const res = await fetch('/api/add', {
|
const res = await fetch('/api/add', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
@ -14,7 +14,6 @@ const link_els = document.querySelectorAll("nav a")
|
|||||||
link_els.forEach((el) => {
|
link_els.forEach((el) => {
|
||||||
el.addEventListener("click", () => {toggle_sidebar(true)});
|
el.addEventListener("click", () => {toggle_sidebar(true)});
|
||||||
})
|
})
|
||||||
console.log(link_els)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -229,7 +229,7 @@ span
|
|||||||
<button class:selected={multiplier==1.5} on:click={() => {multiplier=1.5; custom_mul="…"}}><sup>3</sup>⁄<sub>2</sub>x</button>
|
<button class:selected={multiplier==1.5} on:click={() => {multiplier=1.5; custom_mul="…"}}><sup>3</sup>⁄<sub>2</sub>x</button>
|
||||||
<button class:selected={multiplier==2} on:click="{() => {multiplier=2; custom_mul="…"}}">2x</button>
|
<button class:selected={multiplier==2} on:click="{() => {multiplier=2; custom_mul="…"}}">2x</button>
|
||||||
<button class:selected={multiplier==3} on:click="{() => {multiplier=3; custom_mul="…"}}">3x</button>
|
<button class:selected={multiplier==3} on:click="{() => {multiplier=3; custom_mul="…"}}">3x</button>
|
||||||
<button class:selected={multiplier==custom_mul} on:click={(e) => { console.log(e) ;const el = e.composedPath()[0].children[0]; if(el){ el.focus()}}}>
|
<button class:selected={multiplier==custom_mul} on:click={(e) => { const el = e.composedPath()[0].children[0]; if(el){ el.focus()}}}>
|
||||||
<span class:selected={multiplier==custom_mul}
|
<span class:selected={multiplier==custom_mul}
|
||||||
on:focus={() => { custom_mul="" }
|
on:focus={() => { custom_mul="" }
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@
|
|||||||
|
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
result = JSON.stringify(json)
|
result = JSON.stringify(json)
|
||||||
console.log(result)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
||||||
let month : number;
|
let month : number;
|
||||||
export let active_index;
|
export let active_index;
|
||||||
console.log(active_index)
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
39
src/lib/js/authenticate.ts
Normal file
39
src/lib/js/authenticate.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import type { RequestEvent } from "@sveltejs/kit";
|
||||||
|
import { COOKIE_SECRET } from "$env/static/private";
|
||||||
|
import { verify } from "jsonwebtoken";
|
||||||
|
import { error } from "@sveltejs/kit";
|
||||||
|
import { dbConnect, dbDisconnect } from "../../utils/db";
|
||||||
|
import { User } from "../../models/User";;
|
||||||
|
|
||||||
|
export async function authenticateUser(cookies){
|
||||||
|
// Set your master secret key (replace with your own secret)
|
||||||
|
const masterSecret = COOKIE_SECRET;
|
||||||
|
const secretKey = masterSecret
|
||||||
|
let decoded
|
||||||
|
try{
|
||||||
|
const cookie : string = cookies.get("UserSession")
|
||||||
|
if(cookie){
|
||||||
|
decoded = await verify(cookie, secretKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if(decoded){
|
||||||
|
await dbConnect()
|
||||||
|
let res = await User.findOne({username: decoded.username}, 'access').lean();
|
||||||
|
await dbDisconnect()
|
||||||
|
if(!res){
|
||||||
|
throw error(404, "User for this Cookie does no longer exist")
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
username: decoded.username,
|
||||||
|
access: res.access
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
12
src/models/User.ts
Normal file
12
src/models/User.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
|
const UserSchema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
username: {type: String, required: true, unique: true},
|
||||||
|
pass_hash: {type: String, required: true},
|
||||||
|
salt : {type: String, required: true},
|
||||||
|
access: [String], //rezepte, flims, abrechnung, ...
|
||||||
|
}, {timestamps: true}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const User = mongoose.model("User", UserSchema);
|
14
src/routes/(main)/+layout.svelte
Normal file
14
src/routes/(main)/+layout.svelte
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
import Header from '$lib/components/Header.svelte'
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Header>
|
||||||
|
<ul class=site_header slot=links>
|
||||||
|
<li><a href="/rezepte">Rezepte</a></li>
|
||||||
|
<li><a href="/bilder">Bilder</a></li>
|
||||||
|
<li><a href="/git">Git</a></li>
|
||||||
|
<li><a href="/transmission">Transmission</a></li>
|
||||||
|
</ul>
|
||||||
|
<slot></slot>
|
||||||
|
</Header>
|
18
src/routes/(main)/+page.svelte
Normal file
18
src/routes/(main)/+page.svelte
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><a href="/rezepte">Rezepte</a></h2>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><a href="/bilder">Bilder</a></h2>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><a href="/git">Git</a></h2>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><a href="/transmission">Transmission Web Viewer</a></h2>
|
||||||
|
</section>
|
10
src/routes/(main)/abrechnung/+page.svelte
Normal file
10
src/routes/(main)/abrechnung/+page.svelte
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Header from "$lib/components/Header.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Header>
|
||||||
|
<ul class=site_header slot=links>
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</Header>
|
16
src/routes/(main)/flims/+page.svelte
Normal file
16
src/routes/(main)/flims/+page.svelte
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Header from "$lib/components/Header.svelte";
|
||||||
|
import Calendar from "$lib/components/Calendar.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Header>
|
||||||
|
<ul class=site_header slot=links>
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<Calendar>
|
||||||
|
|
||||||
|
</Calendar>
|
||||||
|
|
||||||
|
|
||||||
|
</Header>
|
41
src/routes/(main)/login/+page.server.ts
Normal file
41
src/routes/(main)/login/+page.server.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { redirect } from "@sveltejs/kit"
|
||||||
|
import type { Actions, PageServerLoad } from "./$types"
|
||||||
|
import { error } from "@sveltejs/kit"
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ locals }) => {
|
||||||
|
return {
|
||||||
|
user: locals.user,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
login: async (event) => {
|
||||||
|
const data = await event.request.formData()
|
||||||
|
const res = await event.fetch('/api/login',
|
||||||
|
{method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: data.get('username'),
|
||||||
|
password: data.get('password'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const jwt = await res.json()
|
||||||
|
if(res.ok){
|
||||||
|
event.cookies.set("UserSession", jwt, {
|
||||||
|
path: "/",
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: "strict",
|
||||||
|
secure: process.env.NODE_ENV === "production",
|
||||||
|
maxAge: 60 * 60 * 24 * 7, // 1 week
|
||||||
|
})
|
||||||
|
|
||||||
|
throw redirect(303, "/")
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw error(401, jwt.message)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
logout: async () => {
|
||||||
|
throw redirect(303, "/logout")
|
||||||
|
},
|
||||||
|
}
|
13
src/routes/(main)/login/+page.svelte
Normal file
13
src/routes/(main)/login/+page.svelte
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<h1>Log In</h1>
|
||||||
|
<form action="?/login" method=POST>
|
||||||
|
<label>
|
||||||
|
Username
|
||||||
|
<input type="text" name="username">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Passwort
|
||||||
|
<input name="password" type="password">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button type="submit">Log In</button>
|
||||||
|
</form>
|
7
src/routes/(main)/logout/+page.server.ts
Normal file
7
src/routes/(main)/logout/+page.server.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { redirect } from "@sveltejs/kit"
|
||||||
|
import type { Actions, PageServerLoad } from "./$types"
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ cookies }) => {
|
||||||
|
cookies.delete("UserSession")
|
||||||
|
redirect(303, "/")
|
||||||
|
}
|
12
src/routes/(main)/logout/+page.svelte
Normal file
12
src/routes/(main)/logout/+page.svelte
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
import { redirect } from "@sveltejs/kit";
|
||||||
|
import { afterNavigate } from '$app/navigation';
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
afterNavigate(() => {
|
||||||
|
redirect(303, "/")
|
||||||
|
})
|
||||||
|
onMount(() => {
|
||||||
|
redirect(303, "/")
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<h1>Log Out</h1>
|
33
src/routes/(main)/register/+page.server.ts
Normal file
33
src/routes/(main)/register/+page.server.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { redirect } from "@sveltejs/kit"
|
||||||
|
import type { Actions, PageServerLoad } from "./$types"
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ locals }) => {
|
||||||
|
return {
|
||||||
|
user: locals.user,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
register: async (event) => {
|
||||||
|
const data = await event.request.formData();
|
||||||
|
const acccess_options = ["rezepte", "abrechnung", "flims"]
|
||||||
|
let enabled_access = []
|
||||||
|
acccess_options.forEach((option) => {
|
||||||
|
if(data.get(option) == 'on'){
|
||||||
|
enabled_access.push(option)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const res = await event.fetch('/api/register',
|
||||||
|
{method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
|
||||||
|
username: data.get('username'),
|
||||||
|
password: data.get('password'),
|
||||||
|
access: enabled_access,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
throw redirect(303, "/login")
|
||||||
|
},
|
||||||
|
}
|
44
src/routes/(main)/register/+page.svelte
Normal file
44
src/routes/(main)/register/+page.svelte
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<script>
|
||||||
|
import { setCookie } from 'svelte-cookie';
|
||||||
|
|
||||||
|
export async function createJWT() {
|
||||||
|
const res = await fetch('/api/login',
|
||||||
|
{method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: "testuser2",
|
||||||
|
password: "password",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const jwt = await res.json()
|
||||||
|
setCookie('UserSession', jwt, {expires: 7})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h1>Register</h1>
|
||||||
|
<form action="?/register" method=POST>
|
||||||
|
<label>
|
||||||
|
Username
|
||||||
|
<input type="text" name="username">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Passwort
|
||||||
|
<input name="password" type="password">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Rezepte
|
||||||
|
<input type="checkbox" name="rezepte">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Abrechnungen
|
||||||
|
<input type="checkbox" name="abrechnung">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Flims
|
||||||
|
<input type="checkbox" name="flims">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button type="submit">Register</button>
|
||||||
|
</form>
|
78
src/routes/(main)/test/+page.svelte
Normal file
78
src/routes/(main)/test/+page.svelte
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<script>
|
||||||
|
import Header from '$lib/components/Header.svelte'
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { get } from 'svelte/store';
|
||||||
|
import { setCookie } from 'svelte-cookie';
|
||||||
|
|
||||||
|
export async function createJWT() {
|
||||||
|
const res = await fetch('/api/login',
|
||||||
|
{method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: "testuser2",
|
||||||
|
password: "password",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const jwt = await res.json()
|
||||||
|
setCookie('UserSession', jwt, {expires: 7})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function registerUserTest(){
|
||||||
|
const res = await fetch('/api/register',
|
||||||
|
{method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: "testuser2",
|
||||||
|
password: "password",
|
||||||
|
access: ["rezepte", "abrechnung", "flims" ]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
console.log("res:", res);
|
||||||
|
const j = await res.json()
|
||||||
|
console.log("response:", j)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function readJWTSS(){
|
||||||
|
const res = await fetch('/api/verify',
|
||||||
|
{method: 'GET',
|
||||||
|
credentials: 'include',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const item = await res.json()
|
||||||
|
console.log(res)
|
||||||
|
console.log(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<Header>
|
||||||
|
<ul class=site_header slot=links>
|
||||||
|
<li><a href="/rezepte">Rezepte</a></li>
|
||||||
|
<li><a href="/bilder">Bilder</a></li>
|
||||||
|
<li><a href="/git">Git</a></li>
|
||||||
|
<li><a href="/transmission">Transmission</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><a href="/rezepte">Rezepte</a></h2>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><a href="/bilder">Bilder</a></h2>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><a href="/git">Git</a></h2>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><a href="/transmission">Transmission Web Viewer</a></h2>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<button on:click={registerUserTest}>Test User Registration</button>
|
||||||
|
<button on:click={createJWT}>Log In</button>
|
||||||
|
<button on:click={readJWTSS}>Test reading cookie</button>
|
||||||
|
</Header>
|
@ -1,6 +1,6 @@
|
|||||||
import type { PageLoad } from "./$types";
|
import type { PageServerLoad } from "./$types";
|
||||||
|
|
||||||
export async function load({ fetch }) {
|
export async function load({ fetch, locals }) {
|
||||||
let current_month = new Date().getMonth() + 1
|
let current_month = new Date().getMonth() + 1
|
||||||
const res_season = await fetch(`/api/items/in_season/` + current_month);
|
const res_season = await fetch(`/api/items/in_season/` + current_month);
|
||||||
const res_all_brief = await fetch(`/api/items/all_brief`);
|
const res_all_brief = await fetch(`/api/items/all_brief`);
|
||||||
@ -9,5 +9,6 @@ export async function load({ fetch }) {
|
|||||||
return {
|
return {
|
||||||
season: item_season,
|
season: item_season,
|
||||||
all_brief: item_all_brief,
|
all_brief: item_all_brief,
|
||||||
|
user: locals.user,
|
||||||
};
|
};
|
||||||
};
|
};
|
@ -35,4 +35,6 @@ h1{
|
|||||||
</MediaScroller>
|
</MediaScroller>
|
||||||
{/each}
|
{/each}
|
||||||
<p>{data.all_brief.length}</p>
|
<p>{data.all_brief.length}</p>
|
||||||
<AddButton></AddButton>
|
{#if data.user && data.user.access.includes("rezepte")}
|
||||||
|
<AddButton></AddButton>
|
||||||
|
{/if}
|
@ -4,9 +4,10 @@ import type { PageLoad } from "./$types";
|
|||||||
//import { dbConnect, dbDisconnect } from '../../../utils/db';
|
//import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
import { error } from "@sveltejs/kit";
|
import { error } from "@sveltejs/kit";
|
||||||
|
|
||||||
export async function load({ fetch, params }) {
|
export async function load({ fetch, params, locals }) {
|
||||||
const res = await fetch(`/api/items/${params.name}`);
|
const res = await fetch(`/api/items/${params.name}`);
|
||||||
const item = await res.json();
|
let item = await res.json();
|
||||||
|
item.user = locals.user
|
||||||
if(res.status != 200){
|
if(res.status != 200){
|
||||||
throw error(res.status, item.message)
|
throw error(res.status, item.message)
|
||||||
}
|
}
|
@ -9,7 +9,7 @@
|
|||||||
import IngredientsPage from '$lib/components/IngredientsPage.svelte';
|
import IngredientsPage from '$lib/components/IngredientsPage.svelte';
|
||||||
import TitleImgParallax from '$lib/components/TitleImgParallax.svelte';
|
import TitleImgParallax from '$lib/components/TitleImgParallax.svelte';
|
||||||
import { afterNavigate } from '$app/navigation';
|
import { afterNavigate } from '$app/navigation';
|
||||||
import {season} from '$lib/js/season_store';
|
import {season} from '$lib/js/season_store';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -242,4 +242,6 @@ h4{
|
|||||||
</div>
|
</div>
|
||||||
</TitleImgParallax>
|
</TitleImgParallax>
|
||||||
|
|
||||||
|
{#if data.user && data.user.access.includes("rezepte")}
|
||||||
<EditButton href="/rezepte/edit/{data.short_name}"></EditButton>
|
<EditButton href="/rezepte/edit/{data.short_name}"></EditButton>
|
||||||
|
{/if}
|
5
src/routes/(rezepte)/rezepte/add/+page.server.ts
Normal file
5
src/routes/(rezepte)/rezepte/add/+page.server.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export async function load({locals}) {
|
||||||
|
return {
|
||||||
|
user: locals.user
|
||||||
|
};
|
||||||
|
};
|
@ -47,7 +47,6 @@
|
|||||||
cooking: "",
|
cooking: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
let password = ""
|
|
||||||
let images = []
|
let images = []
|
||||||
let short_name = ""
|
let short_name = ""
|
||||||
let datecreated = new Date()
|
let datecreated = new Date()
|
||||||
@ -86,14 +85,13 @@
|
|||||||
const data = {
|
const data = {
|
||||||
image: img_local,
|
image: img_local,
|
||||||
name: short_name,
|
name: short_name,
|
||||||
bearer: password,
|
|
||||||
}
|
}
|
||||||
await fetch(`/api/img/add`, {
|
await fetch(`/api/img/add`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
bearer: password,
|
credentials: 'include',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
@ -241,6 +239,25 @@ h1{
|
|||||||
h3{
|
h3{
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
button.action_button{
|
||||||
|
animation: unset !important;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.submit_buttons{
|
||||||
|
display: flex;
|
||||||
|
margin-inline: auto;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin-block: 1rem;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
.submit_buttons p{
|
||||||
|
padding: 0;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<h1>Rezept erstellen</h1>
|
<h1>Rezept erstellen</h1>
|
||||||
|
|
||||||
@ -275,8 +292,6 @@ h3{
|
|||||||
<div class=addendum bind:innerText={addendum} contenteditable></div>
|
<div class=addendum bind:innerText={addendum} contenteditable></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=submit_wrapper>
|
<div class=submit_buttons>
|
||||||
<h2>Neues Rezept hinzufügen:</h2>
|
<button class=action_button on:click={doPost}><p>Hinzufügen</p><Check fill=white width=2rem height=2rem></Check></button>
|
||||||
<input type="password" placeholder=Passwort bind:value={password}>
|
|
||||||
<button class=action_button on:click={doPost}><Check fill=white width=2rem height=2rem></Check></button>
|
|
||||||
</div>
|
</div>
|
@ -1,8 +1,10 @@
|
|||||||
import type { PageLoad } from "./$types";
|
import type { PageLoad } from "./$types";
|
||||||
|
|
||||||
export async function load({ fetch, params}) {
|
export async function load({ fetch, params, locals}) {
|
||||||
let current_month = new Date().getMonth() + 1
|
let current_month = new Date().getMonth() + 1
|
||||||
const res = await fetch(`/api/items/${params.name}`);
|
const res = await fetch(`/api/items/${params.name}`);
|
||||||
const recipe = await res.json();
|
const recipe = await res.json();
|
||||||
return {recipe};
|
return {recipe: recipe,
|
||||||
|
user: locals.user
|
||||||
|
};
|
||||||
};
|
};
|
@ -59,7 +59,6 @@
|
|||||||
let images = data.recipe.images
|
let images = data.recipe.images
|
||||||
|
|
||||||
let short_name = data.recipe.short_name
|
let short_name = data.recipe.short_name
|
||||||
let password
|
|
||||||
let datecreated = data.recipe.datecreated
|
let datecreated = data.recipe.datecreated
|
||||||
let datemodified = new Date()
|
let datemodified = new Date()
|
||||||
|
|
||||||
@ -99,10 +98,10 @@
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: old_short_name,
|
name: old_short_name,
|
||||||
bearer: password,}),
|
}),
|
||||||
headers : {
|
headers : {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
bearer: password
|
credentials: 'include',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if(!res_img.ok){
|
if(!res_img.ok){
|
||||||
@ -117,7 +116,6 @@
|
|||||||
old_short_name,
|
old_short_name,
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
bearer: password,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -145,11 +143,10 @@
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: old_short_name,
|
name: old_short_name,
|
||||||
bearer: password,
|
|
||||||
}),
|
}),
|
||||||
headers : {
|
headers : {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
bearer: password
|
credentials: 'include',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if(!res.ok){
|
if(!res.ok){
|
||||||
@ -161,14 +158,13 @@
|
|||||||
const data = {
|
const data = {
|
||||||
image: img_local,
|
image: img_local,
|
||||||
name: short_name,
|
name: short_name,
|
||||||
bearer: password,
|
|
||||||
}
|
}
|
||||||
const res = await fetch(`/api/img/add`, {
|
const res = await fetch(`/api/img/add`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
bearer: password,
|
credentials: 'include',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
@ -183,18 +179,16 @@
|
|||||||
// case new short_name:
|
// case new short_name:
|
||||||
else if(short_name != old_short_name){
|
else if(short_name != old_short_name){
|
||||||
console.log("MOVING")
|
console.log("MOVING")
|
||||||
console.log("PASSWORD:", password)
|
|
||||||
const res_img = await fetch('/api/img/mv', {
|
const res_img = await fetch('/api/img/mv', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
bearer: password,
|
credentials: 'include',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
old_name: old_short_name,
|
old_name: old_short_name,
|
||||||
new_name: short_name,
|
new_name: short_name,
|
||||||
bearer: password,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if(!res_img.ok){
|
if(!res_img.ok){
|
||||||
@ -223,7 +217,7 @@
|
|||||||
old_short_name,
|
old_short_name,
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
bearer: password,
|
credentials: 'include',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -270,26 +264,6 @@ input:focus-visible
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input[type=password]{
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
padding-block: 0.5em;
|
|
||||||
display: inline;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.submit_wrapper{
|
|
||||||
position: relative;
|
|
||||||
margin-inline: auto;
|
|
||||||
width: max(300px, 50vw)
|
|
||||||
}
|
|
||||||
.submit_wrapper button{
|
|
||||||
position: absolute;
|
|
||||||
right:-1em;
|
|
||||||
bottom: -0.5em;
|
|
||||||
}
|
|
||||||
.submit_wrapper h2{
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
h1{
|
h1{
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
@ -340,9 +314,27 @@ h1{
|
|||||||
h3{
|
h3{
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
button.action_button{
|
||||||
|
animation: unset !important;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.submit_buttons{
|
||||||
|
display: flex;
|
||||||
|
margin-inline: auto;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin-block: 1rem;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
.submit_buttons p{
|
||||||
|
padding: 0;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<h1>Rezept editieren</h1>
|
<h1>Rezept editieren</h1>
|
||||||
|
|
||||||
<CardAdd {card_data} {image_preview_url} ></CardAdd>
|
<CardAdd {card_data} {image_preview_url} ></CardAdd>
|
||||||
|
|
||||||
<h3>Kurzname (für URL):</h3>
|
<h3>Kurzname (für URL):</h3>
|
||||||
@ -374,14 +366,7 @@ h3{
|
|||||||
<div class=addendum bind:innerText={addendum} contenteditable></div>
|
<div class=addendum bind:innerText={addendum} contenteditable></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=submit_wrapper>
|
<div class=submit_buttons>
|
||||||
<h2>Editiertes Rezept abspeichern:</h2>
|
<button class=action_button on:click={doDelete}><p>Löschen</p><Cross fill=white width=2rem height=2rem></Cross></button>
|
||||||
<input type="password" placeholder=Passwort bind:value={password}>
|
<button class=action_button on:click={doEdit}><p>Speichern</p><Check fill=white width=2rem height=2rem></Check></button>
|
||||||
<button class=action_button on:click={doEdit}><Check fill=white width=2rem height=2rem></Check></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=submit_wrapper>
|
|
||||||
<h2>Rezept löschen:</h2>
|
|
||||||
<input type="password" placeholder=Passwort bind:value={password}>
|
|
||||||
<button class=action_button on:click={doDelete}><Cross fill=white width=2rem height=2rem></Cross></button>
|
|
||||||
</div>
|
</div>
|
@ -1,32 +0,0 @@
|
|||||||
<script>
|
|
||||||
import Header from '$lib/components/Header.svelte'
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<Header>
|
|
||||||
<ul class=site_header slot=links>
|
|
||||||
<li><a href="/rezepte">Rezepte</a></li>
|
|
||||||
<li><a href="/bilder">Bilder</a></li>
|
|
||||||
<li><a href="/git">Git</a></li>
|
|
||||||
<li><a href="/transmission">Transmission</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2><a href="/rezepte">Rezepte</a></h2>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2><a href="/bilder">Bilder</a></h2>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2><a href="/git">Git</a></h2>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2><a href="/transmission">Transmission Web Viewer</a></h2>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</Header>
|
|
@ -1,28 +1,30 @@
|
|||||||
import type { RequestHandler } from '@sveltejs/kit';
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
import { Recipe } from '../../../models/Recipe';
|
import { Recipe } from '../../../models/Recipe';
|
||||||
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
import type {RecipeModelType} from '../../../types/types';
|
|
||||||
import { BEARER_TOKEN } from '$env/static/private'
|
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { authenticateUser } from '$lib/js/authenticate';;
|
||||||
// header: use for bearer token for now
|
// header: use for bearer token for now
|
||||||
// recipe json in body
|
// recipe json in body
|
||||||
export const POST: RequestHandler = async ({request}) => {
|
export const POST: RequestHandler = async ({request, cookies}) => {
|
||||||
let message = await request.json()
|
let message = await request.json()
|
||||||
const recipe_json = message.recipe
|
const recipe_json = message.recipe
|
||||||
const bearer_token = message.headers.bearer
|
const user = await authenticateUser(cookies)
|
||||||
if(bearer_token === BEARER_TOKEN){
|
if(!user){
|
||||||
await dbConnect();
|
throw error(401, "Not logged in")
|
||||||
try{
|
}
|
||||||
await Recipe.create(recipe_json);
|
if(!user.access.includes("rezepte")){
|
||||||
} catch(e){
|
throw error(401, "This user does not have permissions to add recipes")
|
||||||
throw error(400, e)
|
}
|
||||||
}
|
else{
|
||||||
await dbDisconnect();
|
await dbConnect();
|
||||||
return new Response(JSON.stringify({msg: "Added recipe successfully"}),{
|
try{
|
||||||
status: 200,
|
await Recipe.create(recipe_json);
|
||||||
});
|
} catch(e){
|
||||||
}
|
throw error(400, e)
|
||||||
else{
|
}
|
||||||
throw error(403, "Password incorrect")
|
await dbDisconnect();
|
||||||
}
|
return new Response(JSON.stringify({msg: "Added recipe successfully"}),{
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -2,23 +2,22 @@ import type { RequestHandler } from '@sveltejs/kit';
|
|||||||
import { Recipe } from '../../../models/Recipe';
|
import { Recipe } from '../../../models/Recipe';
|
||||||
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
import type {RecipeModelType} from '../../../types/types';
|
import type {RecipeModelType} from '../../../types/types';
|
||||||
import { BEARER_TOKEN } from '$env/static/private'
|
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { authenticateUser } from '$lib/js/authenticate';
|
||||||
// header: use for bearer token for now
|
// header: use for bearer token for now
|
||||||
// recipe json in body
|
// recipe json in body
|
||||||
export const POST: RequestHandler = async ({request}) => {
|
export const POST: RequestHandler = async ({request, cookies}) => {
|
||||||
let message = await request.json()
|
let message = await request.json()
|
||||||
const short_name = message.old_short_name
|
|
||||||
const bearer_token = message.headers.bearer
|
const user = await authenticateUser(cookies)
|
||||||
if(bearer_token === BEARER_TOKEN){
|
if(!user) throw error(401, "Need to be logged in")
|
||||||
await dbConnect();
|
if(!user.access.includes("rezepte")) throw error(401, "Insufficient permissions")
|
||||||
|
|
||||||
|
const short_name = message.old_short_name
|
||||||
|
await dbConnect();
|
||||||
await Recipe.findOneAndDelete({short_name: short_name});
|
await Recipe.findOneAndDelete({short_name: short_name});
|
||||||
await dbDisconnect();
|
await dbDisconnect();
|
||||||
return new Response(JSON.stringify({msg: "Deleted recipe successfully"}),{
|
return new Response(JSON.stringify({msg: "Deleted recipe successfully"}),{
|
||||||
status: 200,
|
status: 200,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else{
|
|
||||||
throw error(403, "Password incorrect")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,23 @@ import type { RequestHandler } from '@sveltejs/kit';
|
|||||||
import { Recipe } from '../../../models/Recipe';
|
import { Recipe } from '../../../models/Recipe';
|
||||||
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
import type {RecipeModelType} from '../../../types/types';
|
import type {RecipeModelType} from '../../../types/types';
|
||||||
import { BEARER_TOKEN } from '$env/static/private'
|
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { authenticateUser } from '$lib/js/authenticate';
|
||||||
// header: use for bearer token for now
|
// header: use for bearer token for now
|
||||||
// recipe json in body
|
// recipe json in body
|
||||||
export const POST: RequestHandler = async ({request}) => {
|
export const POST: RequestHandler = async ({request, cookies}) => {
|
||||||
let message = await request.json()
|
let message = await request.json()
|
||||||
const recipe_json = message.recipe
|
const recipe_json = message.recipe
|
||||||
const bearer_token = message.headers.bearer
|
const user = await authenticateUser(cookies)
|
||||||
if(bearer_token === BEARER_TOKEN){
|
console.log(user)
|
||||||
await dbConnect();
|
if(!user){
|
||||||
|
throw error(403, "Not logged in")
|
||||||
|
}
|
||||||
|
else if(!user.access.includes("rezepte")){
|
||||||
|
throw error(403, "This user does not have edit permissions for recipes")
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
await dbConnect();
|
||||||
await Recipe.findOneAndUpdate({short_name: message.old_short_name }, recipe_json);
|
await Recipe.findOneAndUpdate({short_name: message.old_short_name }, recipe_json);
|
||||||
await dbDisconnect();
|
await dbDisconnect();
|
||||||
return new Response(JSON.stringify({msg: "Edited recipe successfully"}),{
|
return new Response(JSON.stringify({msg: "Edited recipe successfully"}),{
|
||||||
@ -19,7 +26,4 @@ export const POST: RequestHandler = async ({request}) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
throw error(403, "Password incorrect")
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import type { RequestHandler } from '@sveltejs/kit';
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
import { BEARER_TOKEN } from '$env/static/private'
|
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
import { IMAGE_DIR } from '$env/static/private'
|
import { IMAGE_DIR } from '$env/static/private'
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
|
import { authenticateUser } from '$lib/js/authenticate';
|
||||||
|
|
||||||
export const POST = (async ({ request }) => {
|
export const POST = (async ({ request, cookies }) => {
|
||||||
const data = await request.json();
|
const data = await request.json();
|
||||||
if(data.bearer === BEARER_TOKEN){
|
const user = await authenticateUser(cookies)
|
||||||
|
if (!user) throw error(401, "Need to be logged in")
|
||||||
|
if (!user.access.includes("rezepte")) throw error(401, "You don't have sufficient permissions for this")
|
||||||
let full_res = new Buffer.from(data.image, 'base64')
|
let full_res = new Buffer.from(data.image, 'base64')
|
||||||
// reduce image size if over 500KB
|
// reduce image size if over 500KB
|
||||||
const MAX_SIZE_KB = 500
|
const MAX_SIZE_KB = 500
|
||||||
@ -41,9 +43,4 @@ export const POST = (async ({ request }) => {
|
|||||||
return new Response(JSON.stringify({msg: "Added image successfully"}),{
|
return new Response(JSON.stringify({msg: "Added image successfully"}),{
|
||||||
status: 200,
|
status: 200,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else{
|
|
||||||
throw error(403, "Password incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
}) satisfies RequestHandler;
|
}) satisfies RequestHandler;
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import type { RequestHandler } from '@sveltejs/kit';
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
import { BEARER_TOKEN } from '$env/static/private'
|
|
||||||
import { IMAGE_DIR } from '$env/static/private'
|
import { IMAGE_DIR } from '$env/static/private'
|
||||||
import { unlink } from 'node:fs';
|
import { unlink } from 'node:fs';
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { authenticateUser } from '$lib/js/authenticate';;
|
||||||
|
|
||||||
export const POST = (async ({ request }) => {
|
export const POST = (async ({ request, cookies }) => {
|
||||||
const data = await request.json();
|
const data = await request.json();
|
||||||
if(data.bearer === BEARER_TOKEN){
|
const user = await authenticateUser(cookies)
|
||||||
|
if(!user) throw error(401, "You need to be logged in")
|
||||||
|
if(!user.access.includes("rezepte")) throw error(401, "Your don't have the required permission for this")
|
||||||
[ "full", "thumb", "placeholder"].forEach((folder) => {
|
[ "full", "thumb", "placeholder"].forEach((folder) => {
|
||||||
unlink(path.join(IMAGE_DIR, "rezepte", folder, data.name + ".webp"), (e) => {
|
unlink(path.join(IMAGE_DIR, "rezepte", folder, data.name + ".webp"), (e) => {
|
||||||
if(e) error(404, "could not delete: " + folder + "/" + data.name + ".webp" + e)
|
if(e) error(404, "could not delete: " + folder + "/" + data.name + ".webp" + e)
|
||||||
@ -16,9 +18,4 @@ export const POST = (async ({ request }) => {
|
|||||||
return new Response(JSON.stringify({msg: "Deleted image successfully"}),{
|
return new Response(JSON.stringify({msg: "Deleted image successfully"}),{
|
||||||
status: 200,
|
status: 200,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else{
|
|
||||||
throw error(403, "Password incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
}) satisfies RequestHandler;
|
}) satisfies RequestHandler;
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import type { RequestHandler } from '@sveltejs/kit';
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
import { BEARER_TOKEN } from '$env/static/private'
|
|
||||||
import { IMAGE_DIR } from '$env/static/private'
|
import { IMAGE_DIR } from '$env/static/private'
|
||||||
import { rename } from 'node:fs';
|
import { rename } from 'node:fs';
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { authenticateUser } from '$lib/js/authenticate';
|
||||||
|
|
||||||
|
export const POST = (async ({ request, cookies }) => {
|
||||||
|
const data = await request.json();
|
||||||
|
const user = await authenticateUser(cookies)
|
||||||
|
if(!user) throw error(401, "need to be logged in")
|
||||||
|
if(!user.access.includes("rezepte")) throw error(401, "You don't have the required permission to do this")
|
||||||
|
|
||||||
export const POST = (async ({ request }) => {
|
|
||||||
const data = await request.json();
|
|
||||||
if(data.bearer === BEARER_TOKEN){
|
|
||||||
[ "full", "thumb", "placeholder"].forEach((folder) => {
|
[ "full", "thumb", "placeholder"].forEach((folder) => {
|
||||||
const old_path = path.join(IMAGE_DIR, "rezepte", folder, data.old_name + ".webp")
|
const old_path = path.join(IMAGE_DIR, "rezepte", folder, data.old_name + ".webp")
|
||||||
rename(old_path, path.join(IMAGE_DIR, "rezepte", folder, data.new_name + ".webp"), (e) => {
|
rename(old_path, path.join(IMAGE_DIR, "rezepte", folder, data.new_name + ".webp"), (e) => {
|
||||||
@ -15,12 +18,8 @@ export const POST = (async ({ request }) => {
|
|||||||
if(e) throw error(500, "could not mv: " + old_path)
|
if(e) throw error(500, "could not mv: " + old_path)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response(JSON.stringify({msg: "Deleted image successfully"}),{
|
return new Response(JSON.stringify({msg: "Deleted image successfully"}),{
|
||||||
status: 200,
|
status: 200,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else{
|
|
||||||
throw error(403, "Password incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
}) satisfies RequestHandler;
|
}) satisfies RequestHandler;
|
||||||
|
45
src/routes/api/login/+server.ts
Normal file
45
src/routes/api/login/+server.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { sign } from 'jsonwebtoken';
|
||||||
|
import { verify} from 'argon2';
|
||||||
|
import { COOKIE_SECRET } from '$env/static/private'
|
||||||
|
import { PEPPER } from '$env/static/private'
|
||||||
|
|
||||||
|
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
|
import { User } from '../../../models/User';
|
||||||
|
|
||||||
|
// header: use for bearer token for now
|
||||||
|
// recipe json in body
|
||||||
|
export const POST: RequestHandler = async ({request}) => {
|
||||||
|
const {username, password} = await request.json()
|
||||||
|
await dbConnect()
|
||||||
|
let res = await User.findOne({username: username}, 'pass_hash salt').lean()
|
||||||
|
await dbDisconnect()
|
||||||
|
if(!res){
|
||||||
|
console.log("NOT FOUND")
|
||||||
|
throw error(401, {message: "wrong password or user does not exist"})
|
||||||
|
}
|
||||||
|
|
||||||
|
const stored_pw = res.pass_hash
|
||||||
|
const salt = res.salt
|
||||||
|
|
||||||
|
const isMatch = await verify(stored_pw, password + PEPPER, {salt})
|
||||||
|
if(!isMatch){
|
||||||
|
throw error(401, {message: "wrong password or user does not exist"})
|
||||||
|
}
|
||||||
|
|
||||||
|
res = await createJWT(username)
|
||||||
|
return new Response(JSON.stringify(res))
|
||||||
|
};
|
||||||
|
|
||||||
|
async function createJWT(username) {
|
||||||
|
const payload = {
|
||||||
|
username: username,
|
||||||
|
};
|
||||||
|
|
||||||
|
const masterSecret = COOKIE_SECRET;
|
||||||
|
const secretKey = masterSecret;
|
||||||
|
const jwt = sign(payload, secretKey);
|
||||||
|
console.log(jwt)
|
||||||
|
return jwt
|
||||||
|
}
|
50
src/routes/api/register/+server.ts
Normal file
50
src/routes/api/register/+server.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { hash } from 'argon2';
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
|
import { ALLOW_REGISTRATION } from '$env/static/private';
|
||||||
|
import { PEPPER } from '$env/static/private';
|
||||||
|
|
||||||
|
import { User } from '../../../models/User';
|
||||||
|
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
|
|
||||||
|
// header: use for bearer token for now
|
||||||
|
// recipe json in body
|
||||||
|
export const POST: RequestHandler = async ({request}) => {
|
||||||
|
if(ALLOW_REGISTRATION){
|
||||||
|
const {username, password, access} = await request.json()
|
||||||
|
const salt = randomBytes(32).toString('hex'); // Generate a random salt
|
||||||
|
|
||||||
|
const pass_hash = await hashPassword(password + PEPPER, salt)
|
||||||
|
await dbConnect();
|
||||||
|
try{
|
||||||
|
await User.create({
|
||||||
|
username: username,
|
||||||
|
pass_hash: pass_hash,
|
||||||
|
salt: salt,
|
||||||
|
access: access,
|
||||||
|
})
|
||||||
|
}catch(e){
|
||||||
|
await dbDisconnect();
|
||||||
|
throw error(400, e);
|
||||||
|
}
|
||||||
|
await dbDisconnect();
|
||||||
|
return new Response(JSON.stringify({message: "User added successfully"}),
|
||||||
|
{status: 200}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw error(401, "user registration currently closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
async function hashPassword(password, salt) {
|
||||||
|
try {
|
||||||
|
const hashedPassword = await hash(password, salt); // Hash the password with the salt and pepper
|
||||||
|
return hashedPassword;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error hashing password:', error);
|
||||||
|
}
|
||||||
|
}
|
62
src/routes/api/verify/+server.ts
Normal file
62
src/routes/api/verify/+server.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { verify } from 'jsonwebtoken';
|
||||||
|
import { hash} from 'argon2';
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
|
import { COOKIE_SECRET } from '$env/static/private'
|
||||||
|
import { ALLOW_REGISTRATION } from '$env/static/private'
|
||||||
|
|
||||||
|
import { User } from '../../../models/User';
|
||||||
|
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
|
|
||||||
|
|
||||||
|
import { getJWTFromRequest } from '../../../utils/cookie';
|
||||||
|
// header: use for bearer token for now
|
||||||
|
// recipe json in body
|
||||||
|
export const GET: RequestHandler = async ({request}) => {
|
||||||
|
const jwt = getJWTFromRequest(request)
|
||||||
|
|
||||||
|
// Set your master secret key (replace with your own secret)
|
||||||
|
const masterSecret = COOKIE_SECRET;
|
||||||
|
const secretKey = masterSecret
|
||||||
|
let decoded
|
||||||
|
try{
|
||||||
|
decoded = await verify(jwt, secretKey);
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
throw error(401, "Cookies have changed, please log in again")
|
||||||
|
}
|
||||||
|
|
||||||
|
await dbConnect()
|
||||||
|
let res = await User.findOne({username: decoded.username}, 'access').lean();
|
||||||
|
await dbDisconnect()
|
||||||
|
if(!res){
|
||||||
|
throw error(404, "User for this Cookie does no longer exist")
|
||||||
|
}
|
||||||
|
return new Response(JSON.stringify({
|
||||||
|
username: decoded.username,
|
||||||
|
access: res.access
|
||||||
|
}), {status: 200})
|
||||||
|
};
|
||||||
|
|
||||||
|
async function hashPassword(password, salt) {
|
||||||
|
try {
|
||||||
|
const hashedPassword = await hash(password, salt); // Hash the password with the salt
|
||||||
|
return hashedPassword;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error hashing password:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function createJWT(username, userSalt) {
|
||||||
|
const payload = {
|
||||||
|
username: username,
|
||||||
|
};
|
||||||
|
|
||||||
|
const masterSecret = COOKIE_SECRET;
|
||||||
|
const secretKey = masterSecret + userSalt;
|
||||||
|
const jwt = sign(payload, secretKey);
|
||||||
|
return jwt
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user