diff --git a/certs/cert.pem b/certs/cert.pem new file mode 100644 index 0000000..1c825f4 --- /dev/null +++ b/certs/cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUBzpjXMENeWGtcDHiOJ6mvvP+C48wDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTAxMTQxNjUwMzhaFw0yNjAx +MTQxNjUwMzhaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCrwtnHsgIcPgiiwbJuwx7qDxIAoDX4TpGCfSemHJyp +OTHbEbYkuTwgFqMhn83fm3DMnn/vorDfWOCpm4OvYIJ4QB9ZeiwDyvmjJQITX0o7 +pm2J0tpmFv4WK9BF+46bq81TtXUG99/ryH9NKFGT0WSdu0XHIqtg9OfVHolw9vPD +PmmxRcPXg+2HziWBQuxqXHazdU31Cf8JDv3iBSYAIOmAsIAp4KuJtfX6MYK4/3jT +huSfGzCnMlieDYj2mUcvCEx4iMk+nshryp5UB6+mgmqC9XgBwPOsqbybd3WnQXaA +gT8bGqjLIYMqJrDVBPcuz+J9i3PFtheHtvmwE82aWSzWAK188NXzK6J2+BJFp97f +dmPaSh5sEFe3twXNeIQgYjQ0b1Y6K9wSyk0mEgitIrp+ARmuSR7a9SHgdLg9FaMg +LkUSrRk46r6P/lO9hSrCusH0cFwMIxgclS0DOPbfwqDIELClSaxO6umKh161W0kP +k38k1DIdrWDUQnb4dMrQdSZrYmpyXhDNsLfHF+hZtNSy+376Utuud0UJSnO6k4QK +JtpPaZRPPBIxcZ3a05JY09pVKHmev+j5U0fcuGWGyRa/cyPsHgU1kGVVOLaC21SJ +h8qWZCqUYby9AsbuTqz9qOpGNmCivmgUESs+h4VZoOOzj+5zGCK5LbIfsLL/nI2+ +QQIDAQABo1MwUTAdBgNVHQ4EFgQUrCJYEE6AckkV62vmB6NpgFSM1QYwHwYDVR0j +BBgwFoAUrCJYEE6AckkV62vmB6NpgFSM1QYwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEApzFmj9XCez3mRLctBCsrTHMueNFrLovscoxb2kWirnIJ +nM0GfLhZcx56+ZXUea5khbIbJrF47Eyh4GVz6ezZnoVBkb2PnD5FzafLxQEhg/bT +9zMWrcGVCe9/Uz1znUXDh7ljj15h60CdhyG3EVCfWxzJs3m/sOGDlA6qDxx0MNdY +PjdQaPPHCH1yDn7vkBWD9SRHJh4/wAl+LAf+3eF9Uz7CRRYA/sYu2dzLLfUXo+My +LJ8JIss2p24pRl6FyHNH5pJ1Uvr0wGfJ9h0rrKixfHgJ3478cxVxns8Ig0BTWJPV +kMdh+rplnnE4CSAaPWnAbD6O4WM7pDQDRXc8kfrcyt0MQ0UYPLwcpQ72umIOkonK +R0FsPLvRe0lmsMeG+Id34CEFtxegbsGCt5OOMKzA3k69JVvLvS85FuLO2a+TrDYg +itCKHVX06oAGa8XAsy1q/s9BMxNWzVDAza6svINaIqubHk1YGJ/hiAvVvBuEKHnT +Gc9uYQEngA3zVjhoiPx2Z6AoSj6Ve2K38JZgPOAfo887W+4a/mguV8QlVv2qeibm +jZKTKglZvH6Iz/v+zM2mWdh+RsyW+hkUum6lH/0vpQnZAUcMK8U5YnAjsFF8tfWy +eJY2gFisHwz6pVY5FwUW/FvaWRIfPTp9CdTHJlhlGTNb3SlLODaM+um46aFaUz0= +-----END CERTIFICATE----- diff --git a/certs/key.pem b/certs/key.pem new file mode 100644 index 0000000..21816ce --- /dev/null +++ b/certs/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +TbEoB7CaVs+VEYE4GJpDXp3V2CQ3 +-----END PRIVATE KEY----- diff --git a/deno.json b/deno.json index 76ef608..ef4b243 100644 --- a/deno.json +++ b/deno.json @@ -22,6 +22,8 @@ ], "imports": { "$fresh/": "https://deno.land/x/fresh@1.7.3/", + "@melvdouc/xml-parser": "jsr:@melvdouc/xml-parser@^0.1.1", + "@popov/jwt": "jsr:@popov/jwt@^1.0.1", "preact": "https://esm.sh/preact@10.22.0", "preact/": "https://esm.sh/preact@10.22.0/", "@preact/signals": "https://esm.sh/*@preact/signals@1.2.2", diff --git a/fresh.config.ts b/fresh.config.ts index e7b63d9..783c68c 100644 --- a/fresh.config.ts +++ b/fresh.config.ts @@ -1,3 +1,9 @@ import { defineConfig } from "$fresh/server.ts"; -export default defineConfig({}); +export default defineConfig({ + server: { + cert: await Deno.readTextFile("certs/cert.pem"), + key: await Deno.readTextFile("certs/key.pem"), + port: 443 + } +}); diff --git a/fresh.gen.ts b/fresh.gen.ts index dd4df1a..cce7416 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -2,21 +2,29 @@ // This file SHOULD be checked into source version control. // This file is automatically updated during development when running `dev.ts`. +import * as $_modules_notes_index from "./routes/(modules)/notes/index.tsx"; import * as $_404 from "./routes/_404.tsx"; import * as $_app from "./routes/_app.tsx"; -import * as $api_joke from "./routes/api/joke.ts"; -import * as $greet_name_ from "./routes/greet/[name].tsx"; +import * as $_middleware from "./routes/_middleware.ts"; import * as $index from "./routes/index.tsx"; +import * as $login from "./routes/login.tsx"; +import * as $logout from "./routes/logout.tsx"; +import * as $partials_about from "./routes/partials/about.tsx"; +import * as $partials_modules from "./routes/partials/modules.tsx"; import * as $Counter from "./islands/Counter.tsx"; import type { Manifest } from "$fresh/server.ts"; const manifest = { routes: { + "./routes/(modules)/notes/index.tsx": $_modules_notes_index, "./routes/_404.tsx": $_404, "./routes/_app.tsx": $_app, - "./routes/api/joke.ts": $api_joke, - "./routes/greet/[name].tsx": $greet_name_, + "./routes/_middleware.ts": $_middleware, "./routes/index.tsx": $index, + "./routes/login.tsx": $login, + "./routes/logout.tsx": $logout, + "./routes/partials/about.tsx": $partials_about, + "./routes/partials/modules.tsx": $partials_modules, }, islands: { "./islands/Counter.tsx": $Counter, diff --git a/mock/base.css b/mock/base.css deleted file mode 100644 index 7a1aa9f..0000000 --- a/mock/base.css +++ /dev/null @@ -1,127 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Jost:ital,wght@0,100..900;1,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap'); - -:root { - color-scheme: light dark; - - --dark-background-color: rgb(30, 30, 42); - --dark-background-color-ui: rgb(50, 50, 62); - --dark-foreground: rgb(241, 241, 255); - - --light-background-color: rgb(225, 225, 237); - --light-background-color-ui: rgb(241, 241, 255); - --light-foreground: rgb(30, 30, 42); - - --wave-color-1: #282830; - --wave-color-2: #383840; - --wave-color-3: #585860; - --wave-color-4: #969698; - - --loader-size: 0.5em; -} - -* { - box-sizing: border-box; -} - -html, body { - margin: 0; - padding: 0; - color: light-dark(var(--light-foreground), var(--dark-foreground)); - background-color: light-dark(var(--light-background-color), var(--dark-background-color)); - height: 100dvh; - width: 100dvw; -} - -body { - display: grid; - font-family: Jost, sans-serif; - font-feature-settings: "ss01" 1; - font-weight: 500; - place-content: center; - padding: 0.75em; -} - -h1 { - font-family: Jost, sans-serif; - margin: 0; - font-size: 1.5em; -} - -@media screen and (max-width: 750px) { - section#main { - font-size: 1em; - } -} - -/** loader */ - -.loader { - margin: 2em 0; - width: calc(4 * var(--loader-size)); - height: calc(4 * var(--loader-size)); - position: relative; - --c:no-repeat linear-gradient(light-dark(var(--light-foreground), var(--dark-foreground)) 0 0); - background: - var(--c) center/100% var(--loader-size), - var(--c) center/var(--loader-size) 100%; -} - -.loader:before { - content:''; - position: absolute; - inset: 0; - background: - var(--c) 0 0, - var(--c) 100% 0, - var(--c) 0 100%, - var(--c) 100% 100%; - background-size: calc(1.55 * var(--loader-size)) calc(1.55 * var(--loader-size)); - animation: l16 1.5s infinite cubic-bezier(0.3,1,0,1); -} - -@keyframes l16 { - 33% {inset:calc(-1 * var(--loader-size));transform: rotate(0deg)} - 66% {inset:calc(-1 * var(--loader-size));transform: rotate(90deg)} - 100% {inset:0 ;transform: rotate(90deg)} -} - -/** waves */ - -section#background { - position: absolute; - bottom: 0; - width: 100%; -} - -.parallax > use { - animation: move-forever 25s cubic-bezier(.55,.5,.45,.5) infinite; -} - -.parallax > use:nth-child(1) { - animation-delay: -2s; - animation-duration: 7s; -} - -.parallax > use:nth-child(2) { - animation-delay: -3s; - animation-duration: 10s; -} - -.parallax > use:nth-child(3) { - animation-delay: -4s; - animation-duration: 13s; -} - -.parallax > use:nth-child(4) { - animation-delay: -5s; - animation-duration: 20s; -} - -@keyframes move-forever { - 0% { - transform: translate3d(-90px,0,0); - } - 100% { - transform: translate3d(85px,0,0); - } -} \ No newline at end of file diff --git a/mock/index.html b/mock/index.html deleted file mode 100644 index fc623d4..0000000 --- a/mock/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - Mock - - - - - - - - - - - - -
-

PolyMPR

-

Random text go brrr

-
- - \ No newline at end of file diff --git a/mock/loading-page.css b/mock/loading-page.css deleted file mode 100644 index 78e7714..0000000 --- a/mock/loading-page.css +++ /dev/null @@ -1,13 +0,0 @@ -section#main { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; - - background-color: light-dark(var(--light-background-color-ui), var(--dark-background-color-ui)); - padding: 2em; - font-size: 2em; - border-radius: 0.5em; - z-index: 999; -} \ No newline at end of file diff --git a/mock/loading.html b/mock/loading.html deleted file mode 100644 index c785837..0000000 --- a/mock/loading.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - Mock - - - - - - - - - - - - -
-

PolyMPR

-

Logging in with amU credentials...

-
-
- - \ No newline at end of file diff --git a/mock/main.css b/mock/main.css deleted file mode 100644 index e2ef1ee..0000000 --- a/mock/main.css +++ /dev/null @@ -1,15 +0,0 @@ -section#main { - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: start; - - background-color: light-dark(var(--light-background-color-ui), var(--dark-background-color-ui)); - padding: 2em; - font-size: 2em; - border-radius: 0.5em; - z-index: 999; - - width: 90dvw; - height: 90dvh; -} \ No newline at end of file diff --git a/routes/(modules)/notes/index.tsx b/routes/(modules)/notes/index.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/_404.tsx b/routes/_404.tsx index c63ae2e..fb42994 100644 --- a/routes/_404.tsx +++ b/routes/_404.tsx @@ -6,22 +6,7 @@ export default function Error404() { 404 - Page not found -
-
- the Fresh logo: a sliced lemon dripping with juice -

404 - Page not found

-

- The page you were looking for doesn't exist. -

- Go back home -
-
+

404

); } diff --git a/routes/_app.tsx b/routes/_app.tsx index 6e4ecf6..0d62d67 100644 --- a/routes/_app.tsx +++ b/routes/_app.tsx @@ -1,16 +1,33 @@ -import { type PageProps } from "$fresh/server.ts"; -export default function App({ Component }: PageProps) { +import { FreshContext } from "$fresh/server.ts"; +import { Partial } from "$fresh/runtime.ts"; + + +export default async function App(request: Request, context: FreshContext) { + const link = context.state.isAuthenticated ? "out" : "in"; + return ( - polympr - + PolyMPR + - - + +
+

PolyMPR

+ +
+ + + + ); -} +} \ No newline at end of file diff --git a/routes/_middleware.ts b/routes/_middleware.ts new file mode 100644 index 0000000..b26a63e --- /dev/null +++ b/routes/_middleware.ts @@ -0,0 +1,39 @@ +import { MiddlewareHandlerContext } from "$fresh/server.ts"; +import { getCookies } from "$std/http/cookie.ts"; +import { isJwtValid } from "@popov/jwt"; + + +const PUBLIC_ROUTES = ["/", "/login", "/logout", "/about", "/contact"]; + +interface State { + isAuthenticated: boolean; +} + + +function isRoutePublic(route: string) { + return PUBLIC_ROUTES.includes(route) || route.match(/\..+$/); +} + + +export const handler = [ + async function checkAuthentication(request: Request, context: MiddlewareHandlerContext) { + const cookies = getCookies(request.headers); + context.state.isAuthenticated = await isJwtValid(cookies["sessionToken"] ?? "", "NEED TO CHANGE THIS KEY FURTHER IN DEV"); + + return context.next(); + }, + async function ensureAuthentication(request: Request, context: MiddlewareHandlerContext) { + const url = new URL(request.url); + + if (!isRoutePublic(url.pathname) && !context.state.isAuthenticated) { + return new Response(null, { + status: 302, + headers: { + Location: "/login" + } + }); + } + + return context.next(); + } +]; \ No newline at end of file diff --git a/routes/api/joke.ts b/routes/api/joke.ts deleted file mode 100644 index db17edd..0000000 --- a/routes/api/joke.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { FreshContext } from "$fresh/server.ts"; - -// Jokes courtesy of https://punsandoneliners.com/randomness/programmer-jokes/ -const JOKES = [ - "Why do Java developers often wear glasses? They can't C#.", - "A SQL query walks into a bar, goes up to two tables and says “can I join you?”", - "Wasn't hard to crack Forrest Gump's password. 1forrest1.", - "I love pressing the F5 key. It's refreshing.", - "Called IT support and a chap from Australia came to fix my network connection. I asked “Do you come from a LAN down under?”", - "There are 10 types of people in the world. Those who understand binary and those who don't.", - "Why are assembly programmers often wet? They work below C level.", - "My favourite computer based band is the Black IPs.", - "What programme do you use to predict the music tastes of former US presidential candidates? An Al Gore Rhythm.", - "An SEO expert walked into a bar, pub, inn, tavern, hostelry, public house.", -]; - -export const handler = (_req: Request, _ctx: FreshContext): Response => { - const randomIndex = Math.floor(Math.random() * JOKES.length); - const body = JOKES[randomIndex]; - return new Response(body); -}; diff --git a/routes/greet/[name].tsx b/routes/greet/[name].tsx deleted file mode 100644 index 9c06827..0000000 --- a/routes/greet/[name].tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { PageProps } from "$fresh/server.ts"; - -export default function Greet(props: PageProps) { - return
Hello {props.params.name}
; -} diff --git a/routes/index.tsx b/routes/index.tsx index fc8061e..d06b743 100644 --- a/routes/index.tsx +++ b/routes/index.tsx @@ -2,24 +2,7 @@ import { useSignal } from "@preact/signals"; import Counter from "../islands/Counter.tsx"; export default function Home() { - const count = useSignal(3); return ( -
-
- the Fresh logo: a sliced lemon dripping with juice -

Welcome to Fresh

-

- Try updating this message in the - ./routes/index.tsx file, and refresh. -

- -
-
+

PolyMPR

); } diff --git a/routes/login.tsx b/routes/login.tsx new file mode 100644 index 0000000..fd0db53 --- /dev/null +++ b/routes/login.tsx @@ -0,0 +1,102 @@ +import { Handlers } from "$fresh/server.ts"; +import { State } from "./_middleware.ts"; +import { parse, type XmlNode } from "@melvdouc/xml-parser"; +import { createJwt } from "@popov/jwt"; +import { setCookie } from "$std/http/cookie.ts"; + + +const SERVICE = "https://localhost/login"; +const CAS = "https://ident.univ-amu.fr/cas"; + + +function getTag(tag: XmlNode): [string, string] { + return [ + tag.tagName.replace("cas:", ""), + tag.children[0].value + ]; +} + + +async function createUserJWT(casResponse: XmlNode): Promise { + const nodes = casResponse.children[1].children.map(getTag); + const fullUserInfos = {}; + + nodes.forEach(([key, value]) => { + if (fullUserInfos[key] && Array.isArray(fullUserInfos[key])) { + fullUserInfos[key].push(value); + } + else if (fullUserInfos[key]) { + fullUserInfos[key] = [fullUserInfos[key], value]; + } + else { + fullUserInfos[key] = value; + } + }); + + const now = Math.floor(Date.now() / 1000); + const oneHour = 60 * 60; + + const payload = { + iss: "PolyMPR", + iat: now, + exp: now + oneHour, + aud: "PolyMPR", + user: fullUserInfos + }; + + const key = "NEED TO CHANGE THIS KEY FURTHER IN DEV"; + return createJwt(payload, key); +} + + +export const handler: Handlers = { + async GET(request, context) { + const url = new URL(request.url); + const ticket = url.searchParams.get("ticket"); + + if (ticket) { + const response = await fetch(`${CAS}/serviceValidate?service=${SERVICE}&ticket=${ticket}`); + const body = parse(await response.text(), "application/xml"); + const casResponse = body[0].children[0]; + + if (casResponse.tagName != "cas:authenticationSuccess") { + return new Response(null, { + status: 302, + headers: { + Location: `${CAS}/login?service=${SERVICE}` + } + }); + } + + const headers = new Headers(); + + setCookie(headers, { + name: "sessionToken", + value: await createUserJWT(casResponse) + }); + headers.set("Location", "/apps"); + + return new Response(null, { + status: 302, + headers + }); + } + + if (context.state.isAuthenticated) { + return new Response(null, { + status: 302, + headers: { + Location: "/apps" + } + }); + } + else { + return new Response(null, { + status: 302, + headers: { + Location: `${CAS}/login?service=${SERVICE}` + } + }); + } + } +}; \ No newline at end of file diff --git a/routes/logout.tsx b/routes/logout.tsx new file mode 100644 index 0000000..730d9d3 --- /dev/null +++ b/routes/logout.tsx @@ -0,0 +1,32 @@ +import { Handlers } from "$fresh/server.ts"; +import { State } from "./_middleware.ts"; +import { deleteCookie } from "$std/http/cookie.ts"; + + +const SERVICE = "https://localhost/"; +const CAS = "https://ident.univ-amu.fr/cas"; + + +export const handler: Handlers = { + async GET(request, context) { + if (context.state.isAuthenticated) { + const headers = new Headers(); + + deleteCookie(headers, "sessionToken", { path: "/" }); + headers.set("Location", `${CAS}/logout?service=${SERVICE}`); + + return new Response(null, { + status: 302, + headers + }); + } + else { + return new Response(null, { + status: 302, + headers: { + Location: "/" + } + }); + } + } +}; \ No newline at end of file diff --git a/routes/partials/about.tsx b/routes/partials/about.tsx new file mode 100644 index 0000000..f4f920c --- /dev/null +++ b/routes/partials/about.tsx @@ -0,0 +1,15 @@ +import { RouteConfig } from "$fresh/server.ts"; +import { Partial } from "$fresh/runtime.ts"; + +export const config: RouteConfig = { + skipAppWrapper: true, + skipInheritedLayouts: true, +}; + +export default async function About(request, context) { + return ( + +

C'est nous wsh

+
+ ); +}; \ No newline at end of file diff --git a/routes/partials/modules.tsx b/routes/partials/modules.tsx new file mode 100644 index 0000000..e69de29 diff --git a/static/favicon.ico b/static/favicon.ico deleted file mode 100644 index 1cfaaa2..0000000 Binary files a/static/favicon.ico and /dev/null differ diff --git a/static/logo.svg b/static/logo.svg deleted file mode 100644 index ef2fbe4..0000000 --- a/static/logo.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/static/styles.css b/static/styles.css deleted file mode 100644 index e94132d..0000000 --- a/static/styles.css +++ /dev/null @@ -1,129 +0,0 @@ - -*, -*::before, -*::after { - box-sizing: border-box; -} -* { - margin: 0; -} -button { - color: inherit; -} -button, [role="button"] { - cursor: pointer; -} -code { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, - "Liberation Mono", "Courier New", monospace; - font-size: 1em; -} -img, -svg { - display: block; -} -img, -video { - max-width: 100%; - height: auto; -} - -html { - line-height: 1.5; - -webkit-text-size-adjust: 100%; - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, - "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, - "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; -} -.transition-colors { - transition-property: background-color, border-color, color, fill, stroke; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} -.my-6 { - margin-bottom: 1.5rem; - margin-top: 1.5rem; -} -.text-4xl { - font-size: 2.25rem; - line-height: 2.5rem; -} -.mx-2 { - margin-left: 0.5rem; - margin-right: 0.5rem; -} -.my-4 { - margin-bottom: 1rem; - margin-top: 1rem; -} -.mx-auto { - margin-left: auto; - margin-right: auto; -} -.px-4 { - padding-left: 1rem; - padding-right: 1rem; -} -.py-8 { - padding-bottom: 2rem; - padding-top: 2rem; -} -.bg-\[\#86efac\] { - background-color: #86efac; -} -.text-3xl { - font-size: 1.875rem; - line-height: 2.25rem; -} -.py-6 { - padding-bottom: 1.5rem; - padding-top: 1.5rem; -} -.px-2 { - padding-left: 0.5rem; - padding-right: 0.5rem; -} -.py-1 { - padding-bottom: 0.25rem; - padding-top: 0.25rem; -} -.border-gray-500 { - border-color: #6b7280; -} -.bg-white { - background-color: #fff; -} -.flex { - display: flex; -} -.gap-8 { - grid-gap: 2rem; - gap: 2rem; -} -.font-bold { - font-weight: 700; -} -.max-w-screen-md { - max-width: 768px; -} -.flex-col { - flex-direction: column; -} -.items-center { - align-items: center; -} -.justify-center { - justify-content: center; -} -.border-2 { - border-width: 2px; -} -.rounded { - border-radius: 0.25rem; -} -.hover\:bg-gray-200:hover { - background-color: #e5e7eb; -} -.tabular-nums { - font-variant-numeric: tabular-nums; -} diff --git a/static/styles/main.css b/static/styles/main.css new file mode 100644 index 0000000..9cedc36 --- /dev/null +++ b/static/styles/main.css @@ -0,0 +1,56 @@ +@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap'); + +:root { + color-scheme: light dark; + + --dark-background-color: rgb(30, 30, 42); + --dark-background-color-ui: rgb(50, 50, 62); + --dark-foreground: rgb(241, 241, 255); + --dark-foreground-dim: rgb(171, 171, 179); + + --light-background-color: rgb(225, 225, 237); + --light-background-color-ui: rgb(241, 241, 255); + --light-foreground: rgb(30, 30, 42); + --light-foreground-dim: rgb(171, 171, 179); + + --accent-color: rgb(38, 157, 217); + + --loader-size: 0.5em; +} + +* { + box-sizing: border-box; + font-family: "Jetbrains Mono"; +} + +html, body { + margin: 0; + padding: 0; +} + +body { + min-height: 100dvh; + display: grid; + grid-template-rows: auto 1fr auto; + background-color: light-dark(var(--light-background-color), var(--dark-background-color)); + color: light-dark(var(--light-foreground), var(--dark-foreground)); +} + +header { + padding: 0.5em 2em; + display: flex; + justify-content: space-between; + align-items: center; +} + +header > nav { + display: flex; + gap: 1em; +} + +footer { + padding: 0.5em; + display: flex; + justify-content: center; + color: light-dark(var(--light-foreground-dim), var(--dark-foreground-dim)); +} \ No newline at end of file diff --git a/test/cas.js b/test/cas.js deleted file mode 100644 index e2d442c..0000000 --- a/test/cas.js +++ /dev/null @@ -1,27 +0,0 @@ -async function main() { - const initResponse = await fetch("https://ident.univ-amu.fr/cas/login"); - const initHTML = await initResponse.text(); - const execution = initHTML.match(/(?<=name="execution" value=").*?(?=")/)[0]; - - const data = new URLSearchParams(); - data.append("username", Deno.env.get("CAS_USERNAME")); - data.append("password", Deno.env.get("CAS_PASSWORD")); - data.append("_eventId", "submit"); - data.append("execution", execution); - - const response = await fetch("https://ident.univ-amu.fr/cas/login", { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded" - }, - body: data.toString() - }); - console.log(response.status) - console.log(response.headers); - - const content = await response.text(); - console.log(content); -} - -main() - diff --git a/test/getInfo.js b/test/getInfo.js deleted file mode 100644 index 269043a..0000000 --- a/test/getInfo.js +++ /dev/null @@ -1,15 +0,0 @@ -const token = Deno.env.get("CAS_TOKEN"); - -async function main() { - const response = await fetch("https://ident.univ-amu.fr/login?service=http://localhost", { - "Cookie": `TGC=${token}` - }); - console.log(response.headers); - - - const responseText = await response.text(); - - console.log(responseText); -} - -main(); \ No newline at end of file