coyotte508 HF staff commited on
Commit
bd9595b
1 Parent(s): 113d498

🛂 Support authentication

Browse files
package.json CHANGED
@@ -16,6 +16,7 @@
16
  "@iconify-json/il": "^1.1.2",
17
  "@sveltejs/adapter-node": "next",
18
  "@sveltejs/kit": "next",
 
19
  "@types/lodash": "^4.14.188",
20
  "@types/marked": "^4.0.7",
21
  "@typescript-eslint/eslint-plugin": "^5.27.0",
@@ -40,6 +41,7 @@
40
  "type": "module",
41
  "dependencies": {
42
  "bcryptjs": "^2.4.3",
 
43
  "form-data": "^4.0.0",
44
  "lodash": "^4.17.21",
45
  "mailgun.js": "^8.0.2",
 
16
  "@iconify-json/il": "^1.1.2",
17
  "@sveltejs/adapter-node": "next",
18
  "@sveltejs/kit": "next",
19
+ "@types/bcryptjs": "^2.4.2",
20
  "@types/lodash": "^4.14.188",
21
  "@types/marked": "^4.0.7",
22
  "@typescript-eslint/eslint-plugin": "^5.27.0",
 
41
  "type": "module",
42
  "dependencies": {
43
  "bcryptjs": "^2.4.3",
44
+ "date-fns": "^2.29.3",
45
  "form-data": "^4.0.0",
46
  "lodash": "^4.17.21",
47
  "mailgun.js": "^8.0.2",
pnpm-lock.yaml CHANGED
@@ -5,6 +5,7 @@ specifiers:
5
  '@iconify-json/il': ^1.1.2
6
  '@sveltejs/adapter-node': next
7
  '@sveltejs/kit': next
 
8
  '@types/lodash': ^4.14.188
9
  '@types/marked': ^4.0.7
10
  '@typescript-eslint/eslint-plugin': ^5.27.0
@@ -13,6 +14,7 @@ specifiers:
13
  '@unocss/preset-uno': ^0.46.3
14
  '@unocss/reset': ^0.46.3
15
  bcryptjs: ^2.4.3
 
16
  eslint: ^8.16.0
17
  eslint-config-prettier: ^8.3.0
18
  eslint-plugin-svelte3: ^4.0.0
@@ -34,6 +36,7 @@ specifiers:
34
 
35
  dependencies:
36
  bcryptjs: 2.4.3
 
37
  form-data: 4.0.0
38
  lodash: 4.17.21
39
  mailgun.js: 8.0.2
@@ -45,6 +48,7 @@ devDependencies:
45
  '@iconify-json/il': 1.1.2
46
  '@sveltejs/adapter-node': 1.0.0-next.100
47
  '@sveltejs/kit': 1.0.0-next.542_svelte@3.52.0+vite@3.2.2
 
48
  '@types/lodash': 4.14.188
49
  '@types/marked': 4.0.7
50
  '@typescript-eslint/eslint-plugin': 5.42.0_6xw5wg2354iw4zujk2f3vyfrzu
@@ -1128,6 +1132,10 @@ packages:
1128
  - supports-color
1129
  dev: true
1130
 
 
 
 
 
1131
  /@types/cookie/0.5.1:
1132
  resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
1133
  dev: true
@@ -1698,6 +1706,11 @@ packages:
1698
  source-map-js: 1.0.2
1699
  dev: true
1700
 
 
 
 
 
 
1701
  /debug/4.3.4:
1702
  resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
1703
  engines: {node: '>=6.0'}
 
5
  '@iconify-json/il': ^1.1.2
6
  '@sveltejs/adapter-node': next
7
  '@sveltejs/kit': next
8
+ '@types/bcryptjs': ^2.4.2
9
  '@types/lodash': ^4.14.188
10
  '@types/marked': ^4.0.7
11
  '@typescript-eslint/eslint-plugin': ^5.27.0
 
14
  '@unocss/preset-uno': ^0.46.3
15
  '@unocss/reset': ^0.46.3
16
  bcryptjs: ^2.4.3
17
+ date-fns: ^2.29.3
18
  eslint: ^8.16.0
19
  eslint-config-prettier: ^8.3.0
20
  eslint-plugin-svelte3: ^4.0.0
 
36
 
37
  dependencies:
38
  bcryptjs: 2.4.3
39
+ date-fns: 2.29.3
40
  form-data: 4.0.0
41
  lodash: 4.17.21
42
  mailgun.js: 8.0.2
 
48
  '@iconify-json/il': 1.1.2
49
  '@sveltejs/adapter-node': 1.0.0-next.100
50
  '@sveltejs/kit': 1.0.0-next.542_svelte@3.52.0+vite@3.2.2
51
+ '@types/bcryptjs': 2.4.2
52
  '@types/lodash': 4.14.188
53
  '@types/marked': 4.0.7
54
  '@typescript-eslint/eslint-plugin': 5.42.0_6xw5wg2354iw4zujk2f3vyfrzu
 
1132
  - supports-color
1133
  dev: true
1134
 
1135
+ /@types/bcryptjs/2.4.2:
1136
+ resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==}
1137
+ dev: true
1138
+
1139
  /@types/cookie/0.5.1:
1140
  resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
1141
  dev: true
 
1706
  source-map-js: 1.0.2
1707
  dev: true
1708
 
1709
+ /date-fns/2.29.3:
1710
+ resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
1711
+ engines: {node: '>=0.11'}
1712
+ dev: false
1713
+
1714
  /debug/4.3.4:
1715
  resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
1716
  engines: {node: '>=6.0'}
src/app.d.ts CHANGED
@@ -1,9 +1,16 @@
1
  // See https://kit.svelte.dev/docs/types#app
2
  // for information about these interfaces
3
  // and what to do when importing types
4
- declare namespace App {
5
- // interface Locals {}
6
- // interface PageData {}
7
- // interface Error {}
8
- // interface Platform {}
 
 
 
 
 
 
 
9
  }
 
1
  // See https://kit.svelte.dev/docs/types#app
2
  // for information about these interfaces
3
  // and what to do when importing types
4
+
5
+ import type { User } from '$lib/types/User';
6
+
7
+ declare global {
8
+ declare namespace App {
9
+ interface Locals {
10
+ user: null | User;
11
+ }
12
+ // interface PageData {}
13
+ // interface Error {}
14
+ // interface Platform {}
15
+ }
16
  }
src/hooks.server.ts ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { users } from '$lib/server/db';
2
+ import type { Handle } from '@sveltejs/kit';
3
+
4
+ export const handle: Handle = async ({ event, resolve }) => {
5
+ const token = event.cookies.get('bergereToken');
6
+
7
+ if (token) {
8
+ event.locals.user = await users.findOne({ token });
9
+ }
10
+
11
+ const response = await resolve(event);
12
+
13
+ return response;
14
+ };
src/routes/+layout.server.ts CHANGED
@@ -16,12 +16,14 @@ export const load: LayoutServerLoad = async (input) => {
16
 
17
  return {
18
  pageData,
19
- pictures: pics
 
20
  };
21
  }
22
 
23
  return {
24
  pageData: null,
25
- pictures: [] as Picture[]
 
26
  };
27
  };
 
16
 
17
  return {
18
  pageData,
19
+ pictures: pics,
20
+ user: !!input.locals.user
21
  };
22
  }
23
 
24
  return {
25
  pageData: null,
26
+ pictures: [] as Picture[],
27
+ user: !!input.locals.user
28
  };
29
  };
src/routes/+layout.svelte CHANGED
@@ -3,10 +3,15 @@
3
  import { slide } from 'svelte/transition';
4
  import '@unocss/reset/normalize.css';
5
  import 'uno.css';
 
6
 
7
- $: path = $page.route.id ?? '';
 
 
 
 
 
8
 
9
- let user: null = null;
10
  let menuOpen = false;
11
  let date = new Date();
12
  </script>
@@ -24,15 +29,19 @@
24
  <meta property="twitter:description" content={$page.data.description} />
25
  {/if}
26
  <meta property="og:type" content={$page.data.type || 'website'} />
27
- <!-- {#if pictures.length > 0}
28
  <meta
29
  property="og:image"
30
- content="{origin}/photos/raw/{shownPicture.storage.slice(-2)[0]._id}"
 
 
 
 
 
31
  />
32
- <meta name="twitter:image" content="{origin}/photos/raw/{shownPicture.storage[0]._id}" />
33
  <meta name="twitter:card" content="summary_large_image" />
34
- {/if} -->
35
- <!-- <meta property="og:url" content="{origin}{path}" /> -->
36
  {#if $page.data.price}
37
  <meta property="product:price:amount" content={$page.data.price} />
38
  <meta property="product:price:currency" content="€" />
@@ -76,7 +85,7 @@
76
  class:text-sunray={path === '/contact'}
77
  class="hidden sm:inline py-4 grow hover:text-sunray">Contact</a
78
  >
79
- {#if user}
80
  <a href="/compte" title="Espace client" class="hidden sm:inline grow text-sunray text-3xl">
81
  <div class="inline-block i-ant-design-user-outlined" />
82
  </a>
@@ -127,7 +136,7 @@
127
  <a href="/contact" class:text-sunray={path === '/contact'} class="my-2 hover:text-sunray"
128
  >Contact</a
129
  >
130
- {#if user}
131
  <a
132
  href="/compte"
133
  title="Espace client"
 
3
  import { slide } from 'svelte/transition';
4
  import '@unocss/reset/normalize.css';
5
  import 'uno.css';
6
+ import type { LayoutData } from './$types';
7
 
8
+ $: path = $page.route?.id ?? '';
9
+
10
+ export let data: LayoutData;
11
+
12
+ $: shownPicture =
13
+ data.pictures.find((p) => p.storage[0].width >= p.storage[0].height) ?? data.pictures[0];
14
 
 
15
  let menuOpen = false;
16
  let date = new Date();
17
  </script>
 
29
  <meta property="twitter:description" content={$page.data.description} />
30
  {/if}
31
  <meta property="og:type" content={$page.data.type || 'website'} />
32
+ {#if shownPicture}
33
  <meta
34
  property="og:image"
35
+ content="{$page.url.protocol}//{$page.url.host}/photos/raw/{shownPicture.storage.slice(-2)[0]
36
+ ._id}"
37
+ />
38
+ <meta
39
+ name="twitter:image"
40
+ content="{$page.url.protocol}//{$page.url.host}/photos/raw/{shownPicture.storage[0]._id}"
41
  />
 
42
  <meta name="twitter:card" content="summary_large_image" />
43
+ {/if}
44
+ <meta property="og:url" content="{$page.url.protocol}//{$page.url.host}{path}" />
45
  {#if $page.data.price}
46
  <meta property="product:price:amount" content={$page.data.price} />
47
  <meta property="product:price:currency" content="€" />
 
85
  class:text-sunray={path === '/contact'}
86
  class="hidden sm:inline py-4 grow hover:text-sunray">Contact</a
87
  >
88
+ {#if data.user}
89
  <a href="/compte" title="Espace client" class="hidden sm:inline grow text-sunray text-3xl">
90
  <div class="inline-block i-ant-design-user-outlined" />
91
  </a>
 
136
  <a href="/contact" class:text-sunray={path === '/contact'} class="my-2 hover:text-sunray"
137
  >Contact</a
138
  >
139
+ {#if data.user}
140
  <a
141
  href="/compte"
142
  title="Espace client"
src/routes/connexion/+layout.server.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { redirect } from '@sveltejs/kit';
2
+ import type { LayoutServerLoad } from './$types';
3
+
4
+ export const load: LayoutServerLoad = (event) => {
5
+ if (event.locals.user) {
6
+ throw redirect(302, '/');
7
+ }
8
+
9
+ return {};
10
+ };
src/routes/connexion/+page.server.ts CHANGED
@@ -2,11 +2,17 @@ import { error, redirect } from '@sveltejs/kit';
2
  import { users } from '$lib/server/db';
3
  import bcrypt from 'bcryptjs';
4
  import type { Actions } from './$types';
 
5
 
6
  export const actions: Actions = {
7
  default: async (event) => {
8
  const data = await event.request.formData();
9
- const email = data.get('email').trim();
 
 
 
 
 
10
 
11
  const user = await users.findOne({ email }, { collation: { locale: 'en', strength: 1 } });
12
 
@@ -14,7 +20,7 @@ export const actions: Actions = {
14
  throw error(404, "Utilisateur non trouvé pour l'email: " + email);
15
  }
16
 
17
- const password = data.get('password').trim();
18
 
19
  if (!(await bcrypt.compare(password as string, user.hash))) {
20
  throw error(401, 'Mauvais mot de passe');
@@ -32,11 +38,11 @@ export const actions: Actions = {
32
  sameSite: 'lax',
33
  secure: true,
34
  httpOnly: true,
35
- maxAge: 24 * 3600 * 365 * 3
36
  });
37
 
38
  if (event.url.searchParams.get('suivant')) {
39
- throw redirect(303, event.url.searchParams.get('suivant'));
40
  }
41
 
42
  return { success: true };
 
2
  import { users } from '$lib/server/db';
3
  import bcrypt from 'bcryptjs';
4
  import type { Actions } from './$types';
5
+ import { addYears } from 'date-fns';
6
 
7
  export const actions: Actions = {
8
  default: async (event) => {
9
  const data = await event.request.formData();
10
+
11
+ if (!data || !data.get('email') || !data.get('password')) {
12
+ throw error(400, 'Pas de login renseigné');
13
+ }
14
+
15
+ const email = data.get('email')!.toString().trim();
16
 
17
  const user = await users.findOne({ email }, { collation: { locale: 'en', strength: 1 } });
18
 
 
20
  throw error(404, "Utilisateur non trouvé pour l'email: " + email);
21
  }
22
 
23
+ const password = data.get('password')!.toString().trim();
24
 
25
  if (!(await bcrypt.compare(password as string, user.hash))) {
26
  throw error(401, 'Mauvais mot de passe');
 
38
  sameSite: 'lax',
39
  secure: true,
40
  httpOnly: true,
41
+ expires: addYears(new Date(), 3)
42
  });
43
 
44
  if (event.url.searchParams.get('suivant')) {
45
+ throw redirect(303, event.url.searchParams.get('suivant')!);
46
  }
47
 
48
  return { success: true };
src/routes/deconnexion/+page.server.ts ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import { redirect } from '@sveltejs/kit';
2
+ import type { Actions } from './$types';
3
+
4
+ export const actions: Actions = {
5
+ default: async (event) => {
6
+ throw redirect(303, event.request.headers.get('referer') ?? '/');
7
+ }
8
+ };