Update Authentication + Build Script

This commit is contained in:
Moritz Utcke
2023-05-18 14:01:54 +04:00
parent 5559f5ca4d
commit 492b790527
22 changed files with 276 additions and 163 deletions

View File

@@ -3,8 +3,6 @@ name: Node.js CD
on: on:
push: push:
branches: [ main ] branches: [ main ]
pull_request:
branches: [ main ]
jobs: jobs:
build: build:
@@ -19,9 +17,10 @@ jobs:
password: "!2Zc727cI1" password: "!2Zc727cI1"
port: 22 port: 22
script: | script: |
cd /home/root/apps/online-energieausweis cd ~/apps/online-energiausweis
git reset --hard HEAD
git clean -f -d
git pull origin main git pull origin main
git status git status
pnpm install --prod pnpm install
pnpm run build bash build.sh
pm2 restart online-energieausweis

View File

@@ -1,24 +0,0 @@
# This workflow will do a clean install of node dependencies,
# build the source code and run tests across different versions of node
# For more information see:
# https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 12
uses: actions/setup-node@v2
with:
node-version: 19.x
- run: npm i
- run: npm run build --if-present
- run: npm test

View File

@@ -1,18 +0,0 @@
name: Docker Image CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the Docker image
run: docker build . --file Dockerfile --tag online-energieausweis:$(date +%s)

37
build.sh Normal file
View File

@@ -0,0 +1,37 @@
#!/bin/bash
# Define your environment variables here
APP_NAME="online-energiausweis"
APP_PORT=3000
DB_CONTAINER_NAME="database"
DB_NAME="main"
DB_USER="main"
DB_PASSWORD="hHMP8cd^N3SnzGRR"
DB_PORT=5432
DB_VOLUME="postgres_data"
git_pull_force() {
git reset --hard HEAD
git clean -f -d
git pull origin main
}
# Zuerst müssen wir neue Änderungen von GitHub pullen.
cd ~/apps/$APP_NAME
git_pull_force;
# Dann bauen wir das Docker Image unserer Application
cd ~/apps/$APP_NAME
docker stop $APP_NAME
docker rm $APP_NAME
docker build -t $APP_NAME .
# Danach machen wir ein Backup der Datenbank, falls bei der Migration etwas schiefgehen sollte.
cd ~/backups/
BACKUP_FILENAME="$(date +"%Y-%m-%d_%H-%M-%S").sql.gz"
docker exec -t $DB_CONTAINER_NAME pg_dumpall -c -U $DB_USER | gzip > $BACKUP_FILENAME
# Und starten unsere App wieder.
docker run -d --name $APP_NAME --link $DB_CONTAINER_NAME -p "$APP_PORT:80" -e DB_CONNECTION=postgresql://$DB_USER:$DB_PASSWORD@${DB_CONTAINER_NAME}:$DB_PORT/$DB_NAME -e DB_PORT=$DB_PORT $APP_NAME
# Das Backup lassen wir da, falls irgendwas schief gehen sollte.

View File

@@ -3,16 +3,16 @@
import { Gebaeude } from "src/lib/Gebaeude"; import { Gebaeude } from "src/lib/Gebaeude";
import HelpLabel from "~/components/HelpLabel.svelte"; import HelpLabel from "~/components/HelpLabel.svelte";
import { auditHeizungGebaeudeBaujahr } from "../Verbrauchsausweis/audits/HeizungGebaeudeBaujahr"; import { auditHeizungGebaeudeBaujahr } from "../Verbrauchsausweis/audits/HeizungGebaeudeBaujahr";
import { addNotification, deleteNotification } from "../Notifications/shared"; import { addNotification, deleteNotification } from "@ibcornelsen/ui";
import TagInput from "../TagInput.svelte"; import TagInput from "../TagInput.svelte";
import { writable } from "svelte/store"; import { writable } from "svelte/store";
export let gebaeude: Gebaeude; export let gebaeude: Gebaeude;
// TODO: Das ist scheise
let tags = writable([]);
$: ausweis = gebaeude.ausweis || new Verbrauchsausweis(); $: ausweis = gebaeude.ausweis || new Verbrauchsausweis();
let baujahr = writable(gebaeude.baujahr);
let baujahrAnlage = writable(gebaeude.ausweis.baujahr_anlage);
</script> </script>
<div class="GRB"> <div class="GRB">
@@ -96,9 +96,7 @@
deleteNotification("HEIZUNG_BAUJAHR") deleteNotification("HEIZUNG_BAUJAHR")
}} }}
className="{auditHeizungGebaeudeBaujahr(gebaeude) ? "linked" : ""}" className="{auditHeizungGebaeudeBaujahr(gebaeude) ? "linked" : ""}"
required bind:tags={baujahrAnlage}
autocomplete="off"
bind:tags
/> />
</div> </div>
</div> </div>
@@ -133,9 +131,7 @@
deleteNotification("GEBAEUDE_BAUJAHR") deleteNotification("GEBAEUDE_BAUJAHR")
}} }}
className="{auditHeizungGebaeudeBaujahr(gebaeude) ? "linked" : ""}" className="{auditHeizungGebaeudeBaujahr(gebaeude) ? "linked" : ""}"
required bind:tags={baujahr}
autocomplete="off"
bind:tags
/> />
</div> </div>
</div> </div>

View File

@@ -13,6 +13,7 @@
/> />
<div class="tooltip"> <div class="tooltip">
<slot></slot> <slot></slot>
<div id="arrow" class="invisible absolute h-3 w-3 bg-inherit before:visible before:absolute before:h-3 before:w-3 right-2 before:rotate-45 before:bg-inherit before:content-['']"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -23,7 +24,7 @@
} }
.tooltip { .tooltip {
@apply absolute left-0 translate-x-[-50%] max-w-[350px] w-max break-words invisible bg-white rounded-lg p-2 shadow-lg top-0 translate-y-[calc(-100%-8px)] transition-all duration-300 opacity-0; @apply absolute -right-1 max-w-[350px] w-max break-words invisible bg-white rounded-lg p-2 shadow-lg top-0 translate-y-[calc(-100%-8px)] transition-all duration-300 opacity-0;
} }
.tooltip-opener:hover .tooltip { .tooltip-opener:hover .tooltip {

View File

@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import cookie from "cookiejs"; import cookie from "cookiejs";
import { addNotification } from "./Notifications/shared"; import { addNotification } from "@ibcornelsen/ui";
let email: string; let email: string;
let password: string; let password: string;

View File

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { addNotification } from "./Notifications/shared"; import { addNotification } from "@ibcornelsen/ui";
let passwort: string; let passwort: string;
let email: string; let email: string;

View File

@@ -3,9 +3,9 @@
let tag = ""; let tag = "";
export let tags: Writable<string[]> = writable([]); export let tags: Writable<any[]> = writable([]);
export let addKeys: number[] = [13]; export let addKeys: number[] = [13, 32];
export let maxTags: number; export let maxTags: number = Infinity;
export let onlyUnique: boolean = false; export let onlyUnique: boolean = false;
export let removeKeys: number[] = [8]; export let removeKeys: number[] = [8];
export let placeholder: string = ""; export let placeholder: string = "";
@@ -13,26 +13,26 @@
export let allowDrop: boolean = false; export let allowDrop: boolean = false;
export let splitWith: string = ","; export let splitWith: string = ",";
export let name: string = ""; export let name: string = "";
export let id: string = "";
export let allowBlur: boolean = true;
export let disable: boolean = false; export let disable: boolean = false;
export let minChars: number = 0; export let minChars: number = 0;
export let labelText;
export let labelShow;
export let readonly: boolean = false; export let readonly: boolean = false;
export let onTagClick: Function; export let onTagClick: Function = ()=>{};
export let onFocusIn: () => any; export let onFocusIn: () => any = () => {};
export let onFocusOut: () => any; export let onFocusOut: () => any = () => {};
export let className: string; export let className: string = "";
function addTag(tag: string) { function addTag(tag: string) {
if (onlyUnique && $tags.indexOf(tag) > -1) { if ((onlyUnique && $tags.indexOf(tag) > -1) || maxTags == $tags.length) {
tag = ""; tag = "";
return; return;
} }
if (minChars > tag.length) {
return;
}
tags.update(value => { tags.update(value => {
return [...value, tag]; return [...value, tag].sort((a,b) => a-b);
}) })
} }
@@ -82,7 +82,8 @@
on:focusin={onFocusIn} on:focusin={onFocusIn}
on:focusout={onFocusOut} on:focusout={onFocusOut}
class="border-none h-full w-full {className}" class="border-none h-full w-full {className}"
disabled={disable || readonly} disabled={disable}
readonly={readonly}
autocomplete="off" autocomplete="off"
{...$$restProps} {...$$restProps}
/> />

View File

@@ -11,10 +11,8 @@
import moment from "moment"; import moment from "moment";
import BilderZusatzsysteme from "../Ausweis/BilderZusatzsysteme.svelte"; import BilderZusatzsysteme from "../Ausweis/BilderZusatzsysteme.svelte";
import { Gebaeude } from "src/lib/Gebaeude"; import { Gebaeude } from "src/lib/Gebaeude";
import { hideLinkedElement, notifications } from "../Notifications/shared";
import { gebaeude } from "./shared"; import { gebaeude } from "./shared";
import RawNotificationWrapper from "../Notifications/RawNotificationWrapper.svelte"; import { RawNotificationWrapper, RawNotification, notifications } from "@ibcornelsen/ui";
import RawNotification from "../Notifications/RawNotification.svelte";
import { auditHeizungGebaeudeBaujahr } from "./audits/HeizungGebaeudeBaujahr"; import { auditHeizungGebaeudeBaujahr } from "./audits/HeizungGebaeudeBaujahr";
import { AuditType, hidden } from "./audits/hidden"; import { AuditType, hidden } from "./audits/hidden";
import { auditBedarfsausweisBenoetigt } from "./audits/BedarfsausweisBenoetigt"; import { auditBedarfsausweisBenoetigt } from "./audits/BedarfsausweisBenoetigt";
@@ -26,9 +24,9 @@
$gebaeude.ausweis = new Verbrauchsausweis(); $gebaeude.ausweis = new Verbrauchsausweis();
$gebaeude.ausweis.gebaeude = $gebaeude; $gebaeude.ausweis.gebaeude = $gebaeude;
if (uid) { if (uid) {
(async () => { async () => {
const result = await fetch(`/api/verbrauchsausweis?uid=${uid}`, { const result = await fetch(`/api/verbrauchsausweis?uid=${uid}`, {
method: "GET" method: "GET",
}); });
const json = await result.json(); const json = await result.json();
@@ -38,14 +36,14 @@
$gebaeude.ausweis = new Verbrauchsausweis(json.data.ausweis); $gebaeude.ausweis = new Verbrauchsausweis(json.data.ausweis);
$gebaeude.ausweis.gebaeude = $gebaeude; $gebaeude.ausweis.gebaeude = $gebaeude;
} }
}) };
} }
$: ausweis = $gebaeude.ausweis || new Verbrauchsausweis(); $: ausweis = $gebaeude.ausweis || new Verbrauchsausweis();
function automatischAusfüllen() { function automatischAusfüllen() {
$gebaeude.baujahr = 1962; $gebaeude.baujahr = [1962];
ausweis.baujahr_anlage = 1952; ausweis.baujahr_anlage = [1952];
$gebaeude.saniert = true; $gebaeude.saniert = true;
$gebaeude.einheiten = 1; $gebaeude.einheiten = 1;
ausweis.ausstellgrund = "Vermietung"; ausweis.ausstellgrund = "Vermietung";
@@ -224,7 +222,8 @@
type="checkbox" type="checkbox"
class="IGwwbool" class="IGwwbool"
name="IGwwbool" name="IGwwbool"
bind:checked={ausweis.kennwerte.warmwasser_enthalten} bind:checked={ausweis.kennwerte
.warmwasser_enthalten}
/>Warmwasser im Verbrauch enthalten</label />Warmwasser im Verbrauch enthalten</label
> >
</div> </div>
@@ -451,61 +450,72 @@
</form> </form>
<RawNotificationWrapper> <RawNotificationWrapper>
{#each Object.entries($notifications) as [uid, notification] (uid)} {#each Object.entries($notifications) as [uid, notification] (uid)}
<RawNotification notification={{...notification, uid }}> <RawNotification notification={{ ...notification, uid }}>
{@html notification.subtext} {@html notification.subtext}
</RawNotification> </RawNotification>
{/each} {/each}
{#if auditBedarfsausweisBenoetigt($gebaeude)} {#if auditBedarfsausweisBenoetigt($gebaeude)}
<RawNotification notification={{ <RawNotification
message: "Bedarfsausweis benötigt!", notification={{
timeout: 0, message: "Bedarfsausweis benötigt!",
uid: "BEDARFSAUSWEIS", timeout: 0,
dismissable: false, uid: "BEDARFSAUSWEIS",
type: "info" dismissable: false,
}}> type: "info",
Sie benötigen einen Bedarfsausweis. <a href='/bedarfsausweis'>Bitte führen Sie hier Ihre Eingabe für den Bedarfsausweis fort</a>. }}
>
Sie benötigen einen Bedarfsausweis. <a href="/bedarfsausweis"
>Bitte führen Sie hier Ihre Eingabe für den Bedarfsausweis fort</a
>.
</RawNotification> </RawNotification>
{/if} {/if}
{#if auditHeizungGebaeudeBaujahr($gebaeude)} {#if auditHeizungGebaeudeBaujahr($gebaeude)}
<RawNotification notification={{ <RawNotification
message: "Plausibilitätsprüfung", notification={{
timeout: 0, message: "Plausibilitätsprüfung",
uid: "HEIZUNG_VOR_GEBAEUDE", timeout: 0,
dismissable: true, uid: "HEIZUNG_VOR_GEBAEUDE",
onUserDismiss: () => { dismissable: true,
hidden.add(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR) onUserDismiss: () => {
$gebaeude = $gebaeude; hidden.add(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR);
}, $gebaeude = $gebaeude;
type: "warning" },
}}> type: "warning",
Sie haben angegeben, dass ihre Heizung vor ihrem Gebäude konstruiert wurde. Sind sie sich sicher, dass das stimmt? }}
>
Sie haben angegeben, dass ihre Heizung vor ihrem Gebäude konstruiert
wurde. Sind sie sich sicher, dass das stimmt?
</RawNotification> </RawNotification>
{/if} {/if}
{#if auditVerbrauchAbweichung($gebaeude).length > 0} {#if auditVerbrauchAbweichung($gebaeude).length > 0}
<RawNotification notification={{ <RawNotification
message: "Plausibilitätsprüfung", notification={{
timeout: 0, message: "Plausibilitätsprüfung",
uid: "VERBRAUCH_ABWEICHUNG", timeout: 0,
dismissable: true, uid: "VERBRAUCH_ABWEICHUNG",
onUserDismiss: () => { dismissable: true,
hidden.add(AuditType.VERBRAUCH_ABWEICHUNG) onUserDismiss: () => {
$gebaeude = $gebaeude; hidden.add(AuditType.VERBRAUCH_ABWEICHUNG);
}, $gebaeude = $gebaeude;
type: "warning" },
}}> type: "warning",
Die Abweichung der Verbräuche zwischen Zeitraum {auditVerbrauchAbweichung($gebaeude)[0]} und {auditVerbrauchAbweichung($gebaeude)[1]} beträgt mehr als 25% und sie haben keinen Leerstand angegeben. Sind sie sich sicher, dass das stimmt? }}
</RawNotification> >
Die Abweichung der Verbräuche zwischen Zeitraum {auditVerbrauchAbweichung(
$gebaeude
)[0]} und {auditVerbrauchAbweichung($gebaeude)[1]} beträgt mehr als 25%
und sie haben keinen Leerstand angegeben. Sind sie sich sicher, dass
das stimmt?
</RawNotification>
{/if} {/if}
</RawNotificationWrapper> </RawNotificationWrapper>
<style> <style>
:global(.linked) { :global(.linked) {
@apply border-2 border-red-400; @apply border-2 border-red-400;
} }
</style> </style>

View File

@@ -7,8 +7,8 @@ export function auditHeizungGebaeudeBaujahr(gebaeude: Gebaeude): boolean {
return false; return false;
} }
return ausweis.baujahr_anlage > 1500 && return ausweis.baujahr_anlage[0] > 1500 &&
gebaeude.baujahr > 1500 && gebaeude.baujahr[0] > 1500 &&
ausweis.baujahr_anlage < gebaeude.baujahr ausweis.baujahr_anlage[0] < gebaeude.baujahr[0]
&& !hidden.has(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR) && !hidden.has(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR)
} }

View File

@@ -13,7 +13,10 @@
async function fetchZipCodeInformation() { async function fetchZipCodeInformation() {
const result = await fetch(`/api/zip?zip=${zip}`, { const result = await fetch(`/api/zip?zip=${zip}`, {
method: "GET" method: "GET",
headers: {
"authorization": "Basic " + btoa("user@ib-cornelsen.de:test")
}
}).then(r => r.json()); }).then(r => r.json());
if (result.success === true) { if (result.success === true) {

View File

@@ -3,7 +3,6 @@ import "../style/global.scss"
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
import SidebarLeft from '../components/SidebarLeft.astro'; import SidebarLeft from '../components/SidebarLeft.astro';
import NotificationWrapper from "~/components/Notifications/NotificationWrapper.svelte";
export interface Props { export interface Props {
title: string; title: string;

View File

@@ -1,10 +1,10 @@
--- ---
import "../style/global.scss" import "../style/global.scss";
import Footer from '../components/Footer.astro'; import Footer from "../components/Footer.astro";
import Header from '../components/Header.astro'; import Header from "../components/Header.astro";
import SidebarLeft from '../components/SidebarLeft.astro'; import SidebarLeft from "../components/SidebarLeft.astro";
import SidebarRight from '../components/SidebarRight.astro'; import SidebarRight from "../components/SidebarRight.astro";
import NotificationWrapper from "~/components/Notifications/NotificationWrapper.svelte"; import { NotificationWrapper } from "@ibcornelsen/ui";
export interface Props { export interface Props {
title: string; title: string;
@@ -13,27 +13,27 @@ export interface Props {
const { title } = Astro.props; const { title } = Astro.props;
const schema = JSON.stringify({ const schema = JSON.stringify({
'@context': 'http://schema.org', "@context": "http://schema.org",
'@type': 'Corporation', "@type": "Corporation",
name: 'IB Cornelsen', name: "IB Cornelsen",
alternateName: 'online-energieausweis.org', alternateName: "online-energieausweis.org",
url: 'https://online-energieausweis.org', url: "https://online-energieausweis.org",
logo: 'https://online-energieausweis.org/ib-cornelsen.png', logo: "https://online-energieausweis.org/ib-cornelsen.png",
address: { address: {
'@type': 'PostalAddress', "@type": "PostalAddress",
streetAddress: 'Katendeich 5A', streetAddress: "Katendeich 5A",
addressLocality: 'Hamburg', addressLocality: "Hamburg",
postalCode: '21035', postalCode: "21035",
addressCountry: 'Deutschland', addressCountry: "Deutschland",
email: 'info@online-energieausweis.org', email: "info@online-energieausweis.org",
}, },
contactPoint: { contactPoint: {
'@type': 'ContactPoint', "@type": "ContactPoint",
telephone: '+49-040-209339850', telephone: "+49-040-209339850",
faxNumber: '+49-040-209339859', faxNumber: "+49-040-209339859",
contactType: 'customer service', contactType: "customer service",
areaServed: 'DE', areaServed: "DE",
availableLanguage: 'German', availableLanguage: "German",
}, },
}); });
--- ---
@@ -65,7 +65,10 @@ const schema = JSON.stringify({
content="✅ Jetzt Ihren Energieausweis online erstellen. Erhalten Sie Ihren online Energieausweis rechtssicher und nach aktueller GEG (vormals EnEV) vom Diplom Ingenieur geprüft." content="✅ Jetzt Ihren Energieausweis online erstellen. Erhalten Sie Ihren online Energieausweis rechtssicher und nach aktueller GEG (vormals EnEV) vom Diplom Ingenieur geprüft."
/> />
<meta property="og:url" content="https://online-energieausweis.org/" /> <meta property="og:url" content="https://online-energieausweis.org/" />
<meta property="og:site_name" content="Energieausweis online erstellen" /> <meta
property="og:site_name"
content="Energieausweis online erstellen"
/>
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta <meta
@@ -81,21 +84,23 @@ const schema = JSON.stringify({
content="https://online-energieausweis.org/images/energieausweis-online-erstellen.jpg" content="https://online-energieausweis.org/images/energieausweis-online-erstellen.jpg"
/> />
<title> <title>
{title || 'Energieausweis online erstellen - Online Energieausweis'} {title || "Energieausweis online erstellen - Online Energieausweis"}
</title> </title>
</head> </head>
<body> <body>
<Header /> <Header />
<main class="grid gap-6 p-6 grid-cols-[2fr,6fr,2fr] max-w-[1920px] w-full"> <main
<SidebarLeft></SidebarLeft> class="grid gap-6 p-6 grid-cols-[2fr,6fr,2fr] max-w-[1920px] w-full"
>
<SidebarLeft />
<article class="mainContent"> <article class="mainContent">
<slot /> <slot />
</article> </article>
<SidebarRight></SidebarRight> <SidebarRight />
</main> </main>
<Footer /> <Footer />
<NotificationWrapper client:load></NotificationWrapper> <NotificationWrapper client:load />
</body> </body>
</html> </html>
@@ -117,7 +122,8 @@ const schema = JSON.stringify({
@apply py-1.5 px-4 w-full rounded-lg outline-none text-lg text-slate-700 border bg-gray-50 transition-colors; @apply py-1.5 px-4 w-full rounded-lg outline-none text-lg text-slate-700 border bg-gray-50 transition-colors;
} }
input:hover, input:focus { input:hover,
input:focus {
@apply bg-gray-100; @apply bg-gray-100;
} }

View File

@@ -20,7 +20,7 @@ export class Bedarfsausweis {
public objekt_gebaeudeteil: string = ""; public objekt_gebaeudeteil: string = "";
public objekt_saniert: boolean = false; public objekt_saniert: boolean = false;
public baujahr_gebaeude: number = 0; public baujahr_gebaeude: number = 0;
public baujahr_anlage: number = 0; public baujahr_anlage: number[] = [];
public anzahl_einheiten: number = 0; public anzahl_einheiten: number = 0;
public erstellungsdatum: Date = new Date(); public erstellungsdatum: Date = new Date();

View File

@@ -21,7 +21,7 @@ export class VerbrauchsausweisGewerbe {
public objekt_gebaeudeteil: string = ""; public objekt_gebaeudeteil: string = "";
public objekt_saniert: boolean = false; public objekt_saniert: boolean = false;
public baujahr_gebaeude: number = 0; public baujahr_gebaeude: number = 0;
public baujahr_anlage: number = 0; public baujahr_anlage: number[] = [];
public anzahl_einheiten: number = 0; public anzahl_einheiten: number = 0;
public erstellungsdatum: Date = new Date(); public erstellungsdatum: Date = new Date();

View File

@@ -1,6 +1,5 @@
import { Ausweis } from "./Ausweis/Ausweis"; import { Ausweis } from "./Ausweis/Ausweis";
import { Verbrauchsausweis } from "./Ausweis/Verbrauchsausweis";
import { Dachgeschoss, Lueftungskonzept } from "./Ausweis/types"; import { Dachgeschoss, Lueftungskonzept } from "./Ausweis/types";
import { BitChecker } from "./BitChecker"; import { BitChecker } from "./BitChecker";
@@ -11,7 +10,7 @@ export class Gebaeude {
public strasse: string = ""; public strasse: string = "";
public gebaeudeteil: string = ""; public gebaeudeteil: string = "";
public saniert: boolean = false; public saniert: boolean = false;
public baujahr: number = 0; public baujahr: number[] = [];
public einheiten: number = 0; public einheiten: number = 0;
public wohnflaeche: number = 0; public wohnflaeche: number = 0;
public keller_beheizt: boolean = false; public keller_beheizt: boolean = false;

View File

@@ -5,6 +5,6 @@ export function encodeToken(data: Record<string, any>) {
return token; return token;
} }
export function decodeToken(token: string) { export function decodeToken<T>(token: string): Partial<T> {
return jwt.decode(token, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4"); return jwt.decode(token, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4");
} }

View File

@@ -0,0 +1 @@
export { validateAuthorizationHeader } from "./validate";

View File

@@ -0,0 +1,62 @@
import { decodeToken } from "src/lib/JsonWebToken";
import { validatePassword } from "src/lib/Password";
import { User } from "src/lib/User";
export async function validateAuthorizationHeader(
request: Request,
validAuthenticationMethods: ("Bearer" | "Basic")[]
): Promise<User | null> {
if (!request.headers.has("authorization")) {
return null;
}
const header = request.headers.get("authorization") as string;
const [authorizationType, value] = header.split(" ");
if (authorizationType == "Basic" && validAuthenticationMethods.indexOf("Basic") > -1) {
// Basic user validation;
try {
const [email, password] = Buffer.from(value, "base64")
.toString()
.split(":");
const user = await User.fromEmail(email);
if (!user) {
return null;
}
if (!validatePassword(user.passwort, password)) {
return null;
}
return user;
} catch (e) {
return null;
}
} else if (authorizationType == "Bearer" && validAuthenticationMethods.indexOf("Bearer") > -1) {
const stringToken = Buffer.from(value, "base64").toString();
try {
const token = decodeToken<{ id: number; uid: string; exp: string }>(
stringToken
);
const id = token.id;
if (!id) {
return null;
}
const user = User.fromPrivateId(id);
if (!user) {
return null;
}
return user;
} catch (e) {
return null;
}
} else {
return null;
}
}

34
src/pages/api/token.ts Normal file
View File

@@ -0,0 +1,34 @@
import type { APIRoute } from "astro";
import { success, MissingPropertyError, error } from "../../lib/APIResponse";
import { validatePassword, hashPassword } from "../../lib/Password";
import { User } from "../../lib/User";
import moment from "moment";
import { encodeToken } from "../../lib/JsonWebToken";
/**
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
* @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann.
*/
export const post: APIRoute = async ({ request }) => {
const body = await request.json();
if (!body.hasOwnProperty("email") || !body.hasOwnProperty("password")) {
return MissingPropertyError(["email", "password"]);
}
const user = await User.fromEmail(body.email);
if (!user) {
return error(["Invalid email or password."]);
}
// Validate Password
if (!validatePassword(user.passwort, body.password)) {
return error(["Invalid email or password."]);
}
const expiry = moment().add(2, "days").unix();
const token = encodeToken({ id: user.id, uid: user.uid, exp: expiry })
return success({ token, expires: expiry });
}

View File

@@ -1,12 +1,19 @@
import type { APIRoute } from "astro"; import type { APIRoute } from "astro";
import { success, MissingPropertyError, MissingEntityError, InvalidDataError } from "../../lib/APIResponse"; import { success, MissingPropertyError, MissingEntityError, InvalidDataError, error } from "../../lib/APIResponse";
import { ZIPInformation } from "src/lib/ZIPInformation"; import { ZIPInformation } from "src/lib/ZIPInformation";
import { validateAuthorizationHeader } from "src/lib/server/Authorization";
/** /**
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab. * Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
* @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann. * @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann.
*/ */
export const get: APIRoute = async ({ request }) => { export const get: APIRoute = async ({ request }) => {
const user = await validateAuthorizationHeader(request, ["Bearer", "Basic"]);
if (!user) {
return error(["Invalid authentication credentials!"]);
}
const body = Object.fromEntries(new URLSearchParams(request.url.split("?")[1])) const body = Object.fromEntries(new URLSearchParams(request.url.split("?")[1]))
let result; let result;