From 13006919b3a2a8fa7541828ca17f41ec06c23f6e Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:01:32 +0900 Subject: [PATCH 01/30] update new version --- .vscode/extensions.json | 5 - .vscode/settings.json | 6 - deno.json | 12 -- deps.ts | 15 ++ example/use_kv_store/Dockerfile | 9 - example/use_kv_store/README.md | 15 -- example/use_kv_store/deno.json | 21 --- example/use_kv_store/dev.ts | 5 - example/use_kv_store/docker-compose.yml | 14 -- example/use_kv_store/fresh.gen.ts | 17 -- example/use_kv_store/main.ts | 15 -- example/use_kv_store/routes/_middleware.ts | 23 --- example/use_kv_store/routes/index.tsx | 83 --------- example/use_kv_store/static/favicon.ico | Bin 22382 -> 0 bytes example/use_kv_store/static/logo.svg | 6 - example/use_kv_store/twind.config.ts | 5 - example/use_redis_store/Dockerfile | 7 - example/use_redis_store/README.md | 15 -- example/use_redis_store/components/.keep | 0 example/use_redis_store/deno.json | 20 -- example/use_redis_store/dev.ts | 5 - example/use_redis_store/docker-compose.yml | 23 --- example/use_redis_store/fresh.gen.ts | 17 -- example/use_redis_store/islands/.keep | 0 example/use_redis_store/main.ts | 12 -- example/use_redis_store/routes/_middleware.ts | 26 --- example/use_redis_store/routes/index.tsx | 81 -------- example/use_redis_store/static/favicon.ico | Bin 22382 -> 0 bytes example/use_redis_store/static/logo.svg | 6 - mod.ts | 11 +- src/deps.ts | 8 - src/handlers/cookie_handler.ts | 53 ++++++ src/handlers/deno_kv_handler.ts | 61 ++++++ src/handlers/redis_handler.ts | 59 ++++++ src/mod.ts | 8 - src/plugins/cookie_plugin.ts | 20 ++ src/plugins/cookie_session_plugin.ts | 34 ---- src/plugins/deno_kv_plugin.ts | 20 ++ src/plugins/kv_session_plugin.ts | 34 ---- src/plugins/redis_plugin.ts | 20 ++ src/plugins/redis_session_plugin.ts | 34 ---- src/session.ts | 146 ++++++++------- src/stores/cookie.ts | 123 ------------ src/stores/cookie_option.ts | 4 - src/stores/cookie_store.ts | 123 ++++++++++++ src/stores/deno_kv_store.ts | 151 +++++++++++++++ src/stores/interface.ts | 7 - src/stores/kv.ts | 176 ------------------ src/stores/redis.ts | 172 ----------------- src/stores/redis_store.ts | 120 ++++++++++++ src/type.ts | 101 ++++++++++ src/utils/request.ts | 13 ++ src/utils/response.ts | 14 ++ tests/1_dashboard_test.js | 52 ------ tests/2_route_test.js | 68 ------- tests/3_kvStore_test.js | 84 --------- ...cookie_session_test_plugin_fresh.config.ts | 7 + .../redis_session_test_plugin_fresh.config.ts | 9 + tests/cookie_session_test.ts | 45 +++++ tests/fixture/deno.json | 17 -- tests/fixture/dev.ts | 7 - tests/fixture/fresh.gen.ts | 21 --- tests/fixture/main.ts | 9 - tests/fixture/routes/_middleware.ts | 3 - tests/fixture/routes/dashboard/index.tsx | 21 --- tests/fixture/routes/index.tsx | 89 --------- tests/fixture/routes/other-route.tsx | 11 -- tests/fixture/static/favicon.ico | Bin 22382 -> 0 bytes tests/fixture/static/logo.svg | 6 - tests/plugin/test_plugin.ts | 16 ++ tests/redis_session_test.ts | 57 ++++++ tests/routes/session_test_plugin.tsx_ | 66 +++++++ tests/routes/session_test_route.tsx | 16 ++ tests/session_test.ts | 133 +++++++++++++ tests/wrapper.js | 31 --- 75 files changed, 1209 insertions(+), 1534 deletions(-) delete mode 100644 .vscode/extensions.json delete mode 100644 .vscode/settings.json delete mode 100644 deno.json create mode 100644 deps.ts delete mode 100644 example/use_kv_store/Dockerfile delete mode 100644 example/use_kv_store/README.md delete mode 100644 example/use_kv_store/deno.json delete mode 100644 example/use_kv_store/dev.ts delete mode 100644 example/use_kv_store/docker-compose.yml delete mode 100644 example/use_kv_store/fresh.gen.ts delete mode 100644 example/use_kv_store/main.ts delete mode 100644 example/use_kv_store/routes/_middleware.ts delete mode 100644 example/use_kv_store/routes/index.tsx delete mode 100644 example/use_kv_store/static/favicon.ico delete mode 100644 example/use_kv_store/static/logo.svg delete mode 100644 example/use_kv_store/twind.config.ts delete mode 100644 example/use_redis_store/Dockerfile delete mode 100644 example/use_redis_store/README.md delete mode 100644 example/use_redis_store/components/.keep delete mode 100644 example/use_redis_store/deno.json delete mode 100644 example/use_redis_store/dev.ts delete mode 100644 example/use_redis_store/docker-compose.yml delete mode 100644 example/use_redis_store/fresh.gen.ts delete mode 100644 example/use_redis_store/islands/.keep delete mode 100644 example/use_redis_store/main.ts delete mode 100644 example/use_redis_store/routes/_middleware.ts delete mode 100644 example/use_redis_store/routes/index.tsx delete mode 100644 example/use_redis_store/static/favicon.ico delete mode 100644 example/use_redis_store/static/logo.svg delete mode 100644 src/deps.ts create mode 100644 src/handlers/cookie_handler.ts create mode 100644 src/handlers/deno_kv_handler.ts create mode 100644 src/handlers/redis_handler.ts delete mode 100644 src/mod.ts create mode 100644 src/plugins/cookie_plugin.ts delete mode 100644 src/plugins/cookie_session_plugin.ts create mode 100644 src/plugins/deno_kv_plugin.ts delete mode 100644 src/plugins/kv_session_plugin.ts create mode 100644 src/plugins/redis_plugin.ts delete mode 100644 src/plugins/redis_session_plugin.ts delete mode 100644 src/stores/cookie.ts delete mode 100644 src/stores/cookie_option.ts create mode 100644 src/stores/cookie_store.ts create mode 100644 src/stores/deno_kv_store.ts delete mode 100644 src/stores/interface.ts delete mode 100644 src/stores/kv.ts delete mode 100644 src/stores/redis.ts create mode 100644 src/stores/redis_store.ts create mode 100644 src/type.ts create mode 100644 src/utils/request.ts create mode 100644 src/utils/response.ts delete mode 100644 tests/1_dashboard_test.js delete mode 100644 tests/2_route_test.js delete mode 100644 tests/3_kvStore_test.js create mode 100644 tests/config/cookie_session_test_plugin_fresh.config.ts create mode 100644 tests/config/redis_session_test_plugin_fresh.config.ts create mode 100644 tests/cookie_session_test.ts delete mode 100644 tests/fixture/deno.json delete mode 100755 tests/fixture/dev.ts delete mode 100644 tests/fixture/fresh.gen.ts delete mode 100644 tests/fixture/main.ts delete mode 100644 tests/fixture/routes/_middleware.ts delete mode 100644 tests/fixture/routes/dashboard/index.tsx delete mode 100644 tests/fixture/routes/index.tsx delete mode 100644 tests/fixture/routes/other-route.tsx delete mode 100644 tests/fixture/static/favicon.ico delete mode 100644 tests/fixture/static/logo.svg create mode 100644 tests/plugin/test_plugin.ts create mode 100644 tests/redis_session_test.ts create mode 100644 tests/routes/session_test_plugin.tsx_ create mode 100644 tests/routes/session_test_route.tsx create mode 100644 tests/session_test.ts delete mode 100644 tests/wrapper.js diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 09cf720..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "recommendations": [ - "denoland.vscode-deno" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 7fe6ae6..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "deno.enable": true, - "deno.lint": true, - "editor.defaultFormatter": "denoland.vscode-deno", - "editor.formatOnSave": true -} diff --git a/deno.json b/deno.json deleted file mode 100644 index 5d82a83..0000000 --- a/deno.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "tasks": { - "fixture": "deno run -A --watch=tests/fixture/static/,tests/fixture/routes/ tests/fixture/dev.ts", - "kv": "deno run -A --unstable --watch=example/use_kv_store/static/,example/use_kv_store/routes/ example/use_kv_store/dev.ts" - }, - "imports": { - "$fresh/": "https://deno.land/x/fresh@1.3.1/", - "$std/": "https://deno.land/std@0.195.0/", - "cookiejar": "https://deno.land/x/another_cookiejar@v5.0.3/mod.ts" - }, - "lock": false -} diff --git a/deps.ts b/deps.ts new file mode 100644 index 0000000..22becac --- /dev/null +++ b/deps.ts @@ -0,0 +1,15 @@ +export { + type Cookie, + deleteCookie, + getCookies, + setCookie, +} from "https://deno.land/std@0.207.0/http/mod.ts"; +export { + create as jwtCreate, + decode as jwtDecode, + verify as jwtVerify, +} from "https://deno.land/x/djwt@v3.0.1/mod.ts"; +export type { + MiddlewareHandler, + MiddlewareHandlerContext, +} from "https://deno.land/x/fresh@1.5.4/server.ts"; diff --git a/example/use_kv_store/Dockerfile b/example/use_kv_store/Dockerfile deleted file mode 100644 index 744e513..0000000 --- a/example/use_kv_store/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM denoland/deno:1.35.1 - -RUN apt-get update - -RUN mkdir /usr/src/app -WORKDIR /usr/src/app - - -EXPOSE 8080 \ No newline at end of file diff --git a/example/use_kv_store/README.md b/example/use_kv_store/README.md deleted file mode 100644 index edfb416..0000000 --- a/example/use_kv_store/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Use KV store sample - -This project is fresh project used fresh-session with a KV store - -## Usage - -```sh -$ docker compose build - -$ docker compose up -d - -$ docker compose exec app deno task start - -# Please access with brawser to http://localhost:8000. -``` diff --git a/example/use_kv_store/deno.json b/example/use_kv_store/deno.json deleted file mode 100644 index 4556ddb..0000000 --- a/example/use_kv_store/deno.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "tasks": { - "start": "deno run -A --unstable --watch=static/,routes/ dev.ts" - }, - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "preact" - }, - "imports": { - "$fresh/": "https://deno.land/x/fresh@1.3.1/", - "preact": "https://esm.sh/preact@10.15.1", - "preact/": "https://esm.sh/preact@10.15.1/", - "preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.1.0", - "@preact/signals": "https://esm.sh/*@preact/signals@1.0.3", - "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.0.1", - "twind": "https://esm.sh/twind@0.16.17", - "twind/": "https://esm.sh/twind@0.16.17/", - "fresh-session/": "https://deno.land/x/fresh_session@0.2.2/" - }, - "lock": false -} diff --git a/example/use_kv_store/dev.ts b/example/use_kv_store/dev.ts deleted file mode 100644 index 2d85d6c..0000000 --- a/example/use_kv_store/dev.ts +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env -S deno run -A --watch=static/,routes/ - -import dev from "$fresh/dev.ts"; - -await dev(import.meta.url, "./main.ts"); diff --git a/example/use_kv_store/docker-compose.yml b/example/use_kv_store/docker-compose.yml deleted file mode 100644 index b364993..0000000 --- a/example/use_kv_store/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: "3" -services: - app: - build: - context: . - dockerfile: Dockerfile - privileged: true - command: tail -f /dev/null - ports: - - "8000:8000" - - "35729:35729" - volumes: - - .:/usr/src/app:cached - tty: true diff --git a/example/use_kv_store/fresh.gen.ts b/example/use_kv_store/fresh.gen.ts deleted file mode 100644 index c89a085..0000000 --- a/example/use_kv_store/fresh.gen.ts +++ /dev/null @@ -1,17 +0,0 @@ -// DO NOT EDIT. This file is generated by fresh. -// This file SHOULD be checked into source version control. -// This file is automatically updated during development when running `dev.ts`. - -import * as $0 from "./routes/_middleware.ts"; -import * as $1 from "./routes/index.tsx"; - -const manifest = { - routes: { - "./routes/_middleware.ts": $0, - "./routes/index.tsx": $1, - }, - islands: {}, - baseUrl: import.meta.url, -}; - -export default manifest; diff --git a/example/use_kv_store/main.ts b/example/use_kv_store/main.ts deleted file mode 100644 index 59697cc..0000000 --- a/example/use_kv_store/main.ts +++ /dev/null @@ -1,15 +0,0 @@ -/// -/// -/// -/// -/// - -export const PORT = 8000; - -import { start } from "$fresh/server.ts"; -import manifest from "./fresh.gen.ts"; - -import twindPlugin from "$fresh/plugins/twind.ts"; -import twindConfig from "./twind.config.ts"; - -await start(manifest, { plugins: [twindPlugin(twindConfig)], port: PORT }); diff --git a/example/use_kv_store/routes/_middleware.ts b/example/use_kv_store/routes/_middleware.ts deleted file mode 100644 index 9acb80c..0000000 --- a/example/use_kv_store/routes/_middleware.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MiddlewareHandlerContext } from "$fresh/server.ts"; -import { kvSession, WithSession } from "fresh-session/mod.ts"; -import { PORT } from "../main.ts"; -export type State = WithSession; - -async function sessionHundler( - req: Request, - ctx: MiddlewareHandlerContext, -) { - const session = kvSession(null, { - maxAge: 10, - httpOnly: true, - }); - - if (req.url === `http://localhost:${ctx.localAddr?.port}/`) { - return session(req, ctx); - } - if (req.url === `http://localhost:${PORT}/`) { - return session(req, ctx); - } - return ctx.next(); -} -export const handler = [sessionHundler]; diff --git a/example/use_kv_store/routes/index.tsx b/example/use_kv_store/routes/index.tsx deleted file mode 100644 index 9eb96be..0000000 --- a/example/use_kv_store/routes/index.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { HandlerContext, Handlers, PageProps } from "$fresh/server.ts"; -import { Head } from "$fresh/runtime.ts"; -import { WithSession } from "fresh-session/mod.ts"; -export type SessionData = { session: Record; message?: string }; - -export const handler: Handlers = { - GET(_req: Request, ctx: HandlerContext) { - const { session } = ctx.state; - // console.log(session); - const message = session.flash("message"); - - return ctx.render({ - session: session.data, - message, - }); - }, - async POST(req: Request, ctx: HandlerContext) { - const { session } = ctx.state; - const form = await req.formData(); - - if ( - typeof form.get("method") === "string" && - form.get("method") === "DELETE" - ) { - session.clear(); - session.flash("message", "Delete value!"); - } else { - const text = form.get("new_session_text_value"); - session.set("text", text); - session.flash("message", "Session value update!"); - if (form.get("session_key_rotate")) { - session.keyRotate(); - } - } - - return new Response("", { - status: 303, - headers: { Location: "/" }, - }); - }, -}; - -export default function Index({ data }: PageProps) { - return ( - <> - - frash-session example[denoKV in use] - -
- {/*
{JSON.stringify(data, null, 2)}
*/} -
Flash Message: {data.message}
-
Now Session Value: {data.session.text}
-
-
-
- -
-
- - -
-
- -
-
-
- - -
-
-
- - ); -} diff --git a/example/use_kv_store/static/favicon.ico b/example/use_kv_store/static/favicon.ico deleted file mode 100644 index 1cfaaa2193b0f210107a559f7421569f57a25388..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22382 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 bck@HGWY%2idMme??%p8ZW3z(%VE+9-Ofn0d diff --git a/example/use_kv_store/static/logo.svg b/example/use_kv_store/static/logo.svg deleted file mode 100644 index ef2fbe4..0000000 --- a/example/use_kv_store/static/logo.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/example/use_kv_store/twind.config.ts b/example/use_kv_store/twind.config.ts deleted file mode 100644 index 2a7ac27..0000000 --- a/example/use_kv_store/twind.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Options } from "$fresh/plugins/twind.ts"; - -export default { - selfURL: import.meta.url, -} as Options; diff --git a/example/use_redis_store/Dockerfile b/example/use_redis_store/Dockerfile deleted file mode 100644 index 1a31c89..0000000 --- a/example/use_redis_store/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM denoland/deno:1.35.2 - -RUN apt-get update -RUN mkdir /usr/src/app -WORKDIR /usr/src/app - -EXPOSE 8000 \ No newline at end of file diff --git a/example/use_redis_store/README.md b/example/use_redis_store/README.md deleted file mode 100644 index d44d5c1..0000000 --- a/example/use_redis_store/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Use Redis store sample - -This project is fresh project used fresh-session with redis store. - -## Usage - -```sh -$ docker compose build - -$ docker compose up -d - -$ docker compose exec app deno task start - -# Please access with brawser to http://localhost:8000. -``` diff --git a/example/use_redis_store/components/.keep b/example/use_redis_store/components/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/example/use_redis_store/deno.json b/example/use_redis_store/deno.json deleted file mode 100644 index a0dd345..0000000 --- a/example/use_redis_store/deno.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "tasks": { - "start": "deno run -A --watch=static/,routes/ dev.ts" - }, - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "preact" - }, - "imports": { - "$fresh/": "https://deno.land/x/fresh@1.3.1/", - "preact": "https://esm.sh/preact@10.15.1", - "preact/": "https://esm.sh/preact@10.15.1/", - "preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.1.0", - "@preact/signals": "https://esm.sh/*@preact/signals@1.0.3", - "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.0.1", - "redis/": "https://deno.land/x/redis@v0.25.0/", - "fresh-session/": "https://deno.land/x/fresh_session@0.2.0/" - }, - "lock": false -} diff --git a/example/use_redis_store/dev.ts b/example/use_redis_store/dev.ts deleted file mode 100644 index 2d85d6c..0000000 --- a/example/use_redis_store/dev.ts +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env -S deno run -A --watch=static/,routes/ - -import dev from "$fresh/dev.ts"; - -await dev(import.meta.url, "./main.ts"); diff --git a/example/use_redis_store/docker-compose.yml b/example/use_redis_store/docker-compose.yml deleted file mode 100644 index 0b393e2..0000000 --- a/example/use_redis_store/docker-compose.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: "3" -services: - app: - build: - context: . - dockerfile: Dockerfile - privileged: true - command: tail -f /dev/null - ports: - - "8000:8000" - - "35729:35729" - volumes: - - .:/usr/src/app:cached - tty: true - redis: - image: "redis:latest" - ports: - - "6379:6379" - volumes: - - "redis-data:/data" - -volumes: - redis-data: \ No newline at end of file diff --git a/example/use_redis_store/fresh.gen.ts b/example/use_redis_store/fresh.gen.ts deleted file mode 100644 index c89a085..0000000 --- a/example/use_redis_store/fresh.gen.ts +++ /dev/null @@ -1,17 +0,0 @@ -// DO NOT EDIT. This file is generated by fresh. -// This file SHOULD be checked into source version control. -// This file is automatically updated during development when running `dev.ts`. - -import * as $0 from "./routes/_middleware.ts"; -import * as $1 from "./routes/index.tsx"; - -const manifest = { - routes: { - "./routes/_middleware.ts": $0, - "./routes/index.tsx": $1, - }, - islands: {}, - baseUrl: import.meta.url, -}; - -export default manifest; diff --git a/example/use_redis_store/islands/.keep b/example/use_redis_store/islands/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/example/use_redis_store/main.ts b/example/use_redis_store/main.ts deleted file mode 100644 index 4e5c707..0000000 --- a/example/use_redis_store/main.ts +++ /dev/null @@ -1,12 +0,0 @@ -/// -/// -/// -/// -/// - -export const PORT = 8000; - -import { start } from "$fresh/server.ts"; -import manifest from "./fresh.gen.ts"; - -await start(manifest, { port: PORT }); diff --git a/example/use_redis_store/routes/_middleware.ts b/example/use_redis_store/routes/_middleware.ts deleted file mode 100644 index 7dc2f6b..0000000 --- a/example/use_redis_store/routes/_middleware.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MiddlewareHandlerContext } from "$fresh/server.ts"; -import { redisSession, WithSession } from "fresh-session/mod.ts"; -import { connect } from "redis/mod.ts"; -import { PORT } from "../main.ts"; -export type State = WithSession; - -const redis = await connect({ - hostname: "redis", - port: 6379, -}); - -const session = redisSession(redis, { - maxAge: 10, - httpOnly: true, -}); - -function sessionHundler(req: Request, ctx: MiddlewareHandlerContext) { - if (req.url === `http://localhost:${ctx.localAddr?.port}/`) { - return session(req, ctx); - } - if (req.url === `http://localhost:${PORT}/`) { - return session(req, ctx); - } - return ctx.next(); -} -export const handler = [sessionHundler]; diff --git a/example/use_redis_store/routes/index.tsx b/example/use_redis_store/routes/index.tsx deleted file mode 100644 index 0158846..0000000 --- a/example/use_redis_store/routes/index.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { HandlerContext, Handlers, PageProps } from "$fresh/server.ts"; -import { Head } from "$fresh/runtime.ts"; -import { WithSession } from "fresh-session/mod.ts"; -export type SessionData = { session: Record; message?: string }; - -export const handler: Handlers = { - GET(_req: Request, ctx: HandlerContext) { - const { session } = ctx.state; - const message = session.flash("message"); - - return ctx.render({ - session: session.data, - message, - }); - }, - async POST(req: Request, ctx: HandlerContext) { - const { session } = ctx.state; - const form = await req.formData(); - - if ( - typeof form.get("method") === "string" && - form.get("method") === "DELETE" - ) { - session.clear(); - session.flash("message", "Delete value!"); - } else { - const text = form.get("new_session_text_value"); - session.set("text", text); - session.flash("message", "Session value update!"); - if (form.get("session_key_rotate")) { - session.keyRotate(); - } - } - - return new Response("", { - status: 303, - headers: { Location: "/" }, - }); - }, -}; - -export default function Index({ data }: PageProps) { - return ( - <> - - frash-session example[redis in use] - -
-
Flash Message: {data.message}
-
Now Session Value: {data.session.text}
-
-
-
- -
-
- - -
-
- -
-
-
- - -
-
-
- - ); -} diff --git a/example/use_redis_store/static/favicon.ico b/example/use_redis_store/static/favicon.ico deleted file mode 100644 index 1cfaaa2193b0f210107a559f7421569f57a25388..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22382 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 bck@HGWY%2idMme??%p8ZW3z(%VE+9-Ofn0d diff --git a/example/use_redis_store/static/logo.svg b/example/use_redis_store/static/logo.svg deleted file mode 100644 index ef2fbe4..0000000 --- a/example/use_redis_store/static/logo.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/mod.ts b/mod.ts index a1ca67a..ef639e7 100644 --- a/mod.ts +++ b/mod.ts @@ -1 +1,10 @@ -export * from "./src/mod.ts"; +export * from "./src/plugins/cookie_plugin.ts"; +export * from "./src/plugins/redis_plugin.ts"; +export * from "./src/plugins/deno_kv_plugin.ts"; +export type { + CookieFreshSessionOptions, + DenoKvFreshSessionOptions, + RedisFreshSessionOptions, + Session, + WithSession, +} from "./src/type.ts"; diff --git a/src/deps.ts b/src/deps.ts deleted file mode 100644 index 81bea28..0000000 --- a/src/deps.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type { Plugin, MiddlewareHandlerContext, MiddlewareHandler} from "https://deno.land/x/fresh@1.5.4/server.ts"; -export { - type Cookie, - deleteCookie, - getCookies, - setCookie, -} from "https://deno.land/std@0.207.0/http/mod.ts"; -export { create, decode, verify } from "https://deno.land/x/djwt@v3.0.1/mod.ts"; diff --git a/src/handlers/cookie_handler.ts b/src/handlers/cookie_handler.ts new file mode 100644 index 0000000..7e94898 --- /dev/null +++ b/src/handlers/cookie_handler.ts @@ -0,0 +1,53 @@ +import { MiddlewareHandler, MiddlewareHandlerContext } from "../../deps.ts"; +import { getCookieSession } from "../stores/cookie_store.ts"; +import { + CookieFreshSessionOptions, + RequiredCookieFreshSessionOptions, +} from "../type.ts"; + +const DEFAULT_COOKIE_SESSION_OPTIONS: RequiredCookieFreshSessionOptions = { + excludePath: [], + cookieOptions: { + name: "session", + path: "/", + maxAge: 60 * 60 * 24, + sameSite: "Lax", + secure: true, + httpOnly: true, + domain: "", + }, +}; + +export function getCookieSessionHandler( + options: CookieFreshSessionOptions = DEFAULT_COOKIE_SESSION_OPTIONS, +): MiddlewareHandler { + return async function ( + req: Request, + ctx: MiddlewareHandlerContext, + ): Promise { + const mergedOptions: RequiredCookieFreshSessionOptions = { + ...DEFAULT_COOKIE_SESSION_OPTIONS, + ...options, + cookieOptions: { + ...DEFAULT_COOKIE_SESSION_OPTIONS.cookieOptions, + ...options.cookieOptions, + }, + }; + + if ( + mergedOptions.excludePath.includes(new URL(req.url).pathname) || + ctx.destination != "route" + ) { + return ctx.next(); + } + + const { session, sessionCookieSetter } = await getCookieSession( + req, + mergedOptions.cookieOptions.name, + ); + ctx.state.session = session; + const response = await ctx.next(); + + return sessionCookieSetter(response, mergedOptions.cookieOptions); + }; +} diff --git a/src/handlers/deno_kv_handler.ts b/src/handlers/deno_kv_handler.ts new file mode 100644 index 0000000..f6d66d1 --- /dev/null +++ b/src/handlers/deno_kv_handler.ts @@ -0,0 +1,61 @@ +import { MiddlewareHandler, MiddlewareHandlerContext } from "../../deps.ts"; +import { getDenoKvSession } from "../stores/deno_kv_store.ts"; +import { + DenoKvFreshSessionOptions, + RequiredDenoKvFreshSessionOptions, +} from "../type.ts"; + +const DEFAULT_DENO_KV_SESSION_OPTIONS: Omit< + RequiredDenoKvFreshSessionOptions, + "client" +> = { + keyPrefix: "session", + excludePath: [], + baseKeyPath: [], + cookieOptions: { + name: "session", + path: "/", + maxAge: 60 * 60 * 24, + sameSite: "Lax", + secure: true, + httpOnly: true, + domain: "", + }, +}; + +export function getDenoKvSessionHandler( + options: DenoKvFreshSessionOptions, +): MiddlewareHandler { + return async function ( + req: Request, + ctx: MiddlewareHandlerContext, + ): Promise { + const mergedOptions: RequiredDenoKvFreshSessionOptions = { + ...DEFAULT_DENO_KV_SESSION_OPTIONS, + ...options, + cookieOptions: { + ...DEFAULT_DENO_KV_SESSION_OPTIONS.cookieOptions, + ...options.cookieOptions, + }, + }; + + if ( + mergedOptions.excludePath.includes(new URL(req.url).pathname) || + ctx.destination != "route" + ) { + return ctx.next(); + } + + const { session, sessionCookieSetter } = await getDenoKvSession( + req, + mergedOptions.cookieOptions.name, + mergedOptions.baseKeyPath, + mergedOptions.keyPrefix, + mergedOptions.client, + ); + ctx.state.session = session; + const response = await ctx.next(); + + return sessionCookieSetter(response, mergedOptions.cookieOptions); + }; +} diff --git a/src/handlers/redis_handler.ts b/src/handlers/redis_handler.ts new file mode 100644 index 0000000..05e16fc --- /dev/null +++ b/src/handlers/redis_handler.ts @@ -0,0 +1,59 @@ +import { MiddlewareHandler, MiddlewareHandlerContext } from "../../deps.ts"; +import { getRedisSession } from "../stores/redis_store.ts"; +import { + RedisFreshSessionOptions, + RequiredRedisFreshSessionOptions, +} from "../type.ts"; + +const DEFAULT_REDIS_SESSION_OPTIONS: Omit< + RequiredRedisFreshSessionOptions, + "client" +> = { + keyPrefix: "session", + excludePath: [], + cookieOptions: { + name: "session", + path: "/", + maxAge: 60 * 60 * 24, + sameSite: "Lax", + secure: true, + httpOnly: true, + domain: "", + }, +}; + +export function getRedisSessionHandler( + options: RedisFreshSessionOptions, +): MiddlewareHandler { + return async function ( + req: Request, + ctx: MiddlewareHandlerContext, + ): Promise { + const mergedOptions: RequiredRedisFreshSessionOptions = { + ...DEFAULT_REDIS_SESSION_OPTIONS, + ...options, + cookieOptions: { + ...DEFAULT_REDIS_SESSION_OPTIONS.cookieOptions, + ...options.cookieOptions, + }, + }; + + if ( + mergedOptions.excludePath.includes(new URL(req.url).pathname) || + ctx.destination != "route" + ) { + return ctx.next(); + } + + const { session, sessionCookieSetter } = await getRedisSession( + req, + mergedOptions.cookieOptions.name, + mergedOptions.keyPrefix, + mergedOptions.client, + ); + ctx.state.session = session; + const response = await ctx.next(); + + return sessionCookieSetter(response, mergedOptions.cookieOptions); + }; +} diff --git a/src/mod.ts b/src/mod.ts deleted file mode 100644 index 001fa58..0000000 --- a/src/mod.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from "./stores/cookie.ts"; -export * from "./stores/redis.ts"; -export * from "./stores/kv.ts"; -export * from "./stores/interface.ts"; -export * from "./session.ts"; -export * from "./plugins/cookie_session_plugin.ts"; -export * from "./plugins/redis_session_plugin.ts"; -export * from "./plugins/kv_session_plugin.ts"; diff --git a/src/plugins/cookie_plugin.ts b/src/plugins/cookie_plugin.ts new file mode 100644 index 0000000..8d2ccc1 --- /dev/null +++ b/src/plugins/cookie_plugin.ts @@ -0,0 +1,20 @@ +import { CookieFreshSessionOptions } from "../type.ts"; +import { getCookieSessionHandler } from "../handlers/cookie_handler.ts"; + +export function getCookieSessionPlugin( + middlewarePath = "/", + options?: CookieFreshSessionOptions, +) { + const handler = getCookieSessionHandler(options); + return { + name: "CookieSessionPlugin", + middlewares: [ + { + middleware: { + handler, + }, + path: middlewarePath, + }, + ], + }; +} diff --git a/src/plugins/cookie_session_plugin.ts b/src/plugins/cookie_session_plugin.ts deleted file mode 100644 index 9ea7a81..0000000 --- a/src/plugins/cookie_session_plugin.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { - Plugin, - MiddlewareHandlerContext, - MiddlewareHandler, -} from "../deps.ts"; -import { cookieSession } from "../stores/cookie.ts"; -import { CookieOptions } from "../stores/cookie_option.ts"; -import { sessionModule } from "../stores/interface.ts"; - -export function getCookieSessionHandler(session: sessionModule, excludePath: string[]): MiddlewareHandler { - return function (req: Request, ctx: MiddlewareHandlerContext) { - if (excludePath.includes(new URL(req.url).pathname)) { - return ctx.next(); - } - return session(req, ctx); - }; -} - -export function getCookieSessionPlugin(path = "/", excludePath = [], cookieOptions?: CookieOptions): Plugin { - const session = cookieSession(cookieOptions); - const handler = getCookieSessionHandler(session, excludePath); - - return { - name: "cookieSessionPlugin", - middlewares: [ - { - middleware: { - handler: handler, - }, - path: path, - }, - ], - }; -} diff --git a/src/plugins/deno_kv_plugin.ts b/src/plugins/deno_kv_plugin.ts new file mode 100644 index 0000000..f295e93 --- /dev/null +++ b/src/plugins/deno_kv_plugin.ts @@ -0,0 +1,20 @@ +import { DenoKvFreshSessionOptions } from "../type.ts"; +import { getDenoKvSessionHandler } from "../handlers/deno_kv_handler.ts"; + +export function getDenoKvSessionPlugin( + middlewarePath = "/", + options: DenoKvFreshSessionOptions, +) { + const handler = getDenoKvSessionHandler(options); + return { + name: "RedisSessionPlugin", + middlewares: [ + { + middleware: { + handler, + }, + path: middlewarePath, + }, + ], + }; +} diff --git a/src/plugins/kv_session_plugin.ts b/src/plugins/kv_session_plugin.ts deleted file mode 100644 index 8a6b9d7..0000000 --- a/src/plugins/kv_session_plugin.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { - Plugin, - MiddlewareHandlerContext, - MiddlewareHandler, -} from "../deps.ts"; -import { kvSession } from "../stores/kv.ts"; -import { CookieOptions } from "../stores/cookie_option.ts"; -import { sessionModule } from "../stores/interface.ts"; - -export function getKvSessionHandler(session: sessionModule, excludePath: string[]): MiddlewareHandler { - return function (req: Request, ctx: MiddlewareHandlerContext) { - if (excludePath.includes(new URL(req.url).pathname)) { - return ctx.next(); - } - return session(req, ctx); - }; -} - -export function getKvSessionPlugin(storePath: string|null, path = "/", excludePath = [], cookieOptions?: CookieOptions): Plugin { - const session = kvSession(storePath, cookieOptions); - const handler = getKvSessionHandler(session, excludePath); - - return { - name: "cookieSessionPlugin", - middlewares: [ - { - middleware: { - handler: handler, - }, - path: path, - }, - ], - }; -} diff --git a/src/plugins/redis_plugin.ts b/src/plugins/redis_plugin.ts new file mode 100644 index 0000000..24c411a --- /dev/null +++ b/src/plugins/redis_plugin.ts @@ -0,0 +1,20 @@ +import { RedisFreshSessionOptions } from "../type.ts"; +import { getRedisSessionHandler } from "../handlers/redis_handler.ts"; + +export function getRedisSessionPlugin( + middlewarePath = "/", + options: RedisFreshSessionOptions, +) { + const handler = getRedisSessionHandler(options); + return { + name: "RedisSessionPlugin", + middlewares: [ + { + middleware: { + handler, + }, + path: middlewarePath, + }, + ], + }; +} diff --git a/src/plugins/redis_session_plugin.ts b/src/plugins/redis_session_plugin.ts deleted file mode 100644 index 12bdde5..0000000 --- a/src/plugins/redis_session_plugin.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { - Plugin, - MiddlewareHandlerContext, - MiddlewareHandler, -} from "../deps.ts"; -import { Store, redisSession } from "../stores/redis.ts"; -import { CookieOptions } from "../stores/cookie_option.ts"; -import { sessionModule } from "../stores/interface.ts"; - -export function getRedisSessionHandler(session: sessionModule, excludePath: string[]): MiddlewareHandler { - return function (req: Request, ctx: MiddlewareHandlerContext) { - if (excludePath.includes(new URL(req.url).pathname)) { - return ctx.next(); - } - return session(req, ctx); - }; -} - -export function getRedisSessionPlugin(store: Store, path = "/", excludePath = [], cookieOptions?: CookieOptions): Plugin { - const session = redisSession(store, cookieOptions); - const handler = getRedisSessionHandler(session, excludePath); - - return { - name: "cookieSessionPlugin", - middlewares: [ - { - middleware: { - handler: handler, - }, - path: path, - }, - ], - }; -} diff --git a/src/session.ts b/src/session.ts index 394d00e..b4e66d8 100644 --- a/src/session.ts +++ b/src/session.ts @@ -1,67 +1,81 @@ -export class Session { - #data = new Map(); - #flash = new Map(); - #doDelete = false; - #doKeyRotate = false; - - constructor(data = {}, flash = {}) { - this.#data = new Map(Object.entries(data)); - this.#flash = new Map(Object.entries(flash)); - } - - get data() { - return Object.fromEntries(this.#data); - } - - get flashedData() { - return Object.fromEntries(this.#flash); - } - - get doDelete() { - return this.#doDelete; - } - - get doKeyRotate() { - return this.#doKeyRotate; - } - - set(key: string, value: any) { - this.#data.set(key, value); - - return this; - } - - get(key: string) { - return this.#data.get(key); - } - - has(key: string) { - return this.#data.has(key); - } - - clear() { - this.#data.clear(); - return this; - } - - flash(key: string, value?: any) { - if (value === undefined) { - const flashedValue = this.#flash.get(key); - - this.#flash.delete(key); - - return flashedValue; - } - this.#flash.set(key, value); - - return this; - } - - destroy() { - this.#doDelete = true; - } - - keyRotate() { - this.#doKeyRotate = true; - } +import type { + AllowType, + FlashData, + Session, + SessionData, + SessionDuplicationData, +} from "./type.ts"; + +export function createSession( + { session, flash }: { session: SessionData; flash: FlashData }, +): { + session: Session; + getDuplicateDataFunction: { (): SessionDuplicationData }; +} { + let sessionData: SessionData = (session || {}) as SessionData; + const flashData: FlashData = (flash || {}) as FlashData; + const newFlashData: FlashData = {} as FlashData; + const operations = { + doDestroy: false, + doRotateKey: false, + }; + + let duplicateData: SessionDuplicationData | null = null; + + const sessionObj: Session = { + get(key) { + return sessionData[key]; + }, + set(key, value) { + sessionData[key] = value; + duplicateData = this.getRawData(); + }, + delete(key) { + const { [key]: _removed, ...res } = sessionData; + sessionData = res as SessionData; + duplicateData = this.getRawData(); + }, + list() { + return sessionData; + }, + destroy() { + operations.doDestroy = true; + duplicateData = this.getRawData(); + }, + rotateKey() { + operations.doRotateKey = true; + duplicateData = this.getRawData(); + }, + has(key) { + return key in sessionData; + }, + clear() { + sessionData = {} as SessionData; + duplicateData = this.getRawData(); + }, + flash(key: F, value?: AllowType) { + if (value === undefined) { + return flashData[key]; + } + newFlashData[key] = value; + duplicateData = this.getRawData(); + }, + flashNow(key: F) { + const value = { ...flashData, ...newFlashData }[key]! + delete newFlashData[key]; + duplicateData = this.getRawData(); + return value; + }, + getRawData() { + return { session: sessionData, flash: newFlashData, operations }; + }, + }; + duplicateData = sessionObj.getRawData(); + + return { + session: sessionObj, + getDuplicateDataFunction: () => { + return duplicateData!; + }, + }; } diff --git a/src/stores/cookie.ts b/src/stores/cookie.ts deleted file mode 100644 index 8121ef4..0000000 --- a/src/stores/cookie.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { - create, - decode, - getCookies, - MiddlewareHandlerContext, - setCookie, - verify, -} from "../deps.ts"; -import { type CookieOptions } from "./cookie_option.ts"; -import { Session } from "../session.ts"; -import type { WithSession } from "./interface.ts"; - -export function key() { - const key = Deno.env.get("APP_KEY"); - - if (!key) { - console.warn( - "[FRESH SESSION] Warning: We didn't detect a env variable `APP_KEY`, if you are in production please fix this ASAP to avoid any security issue.", - ); - } - - return crypto.subtle.importKey( - "raw", - new TextEncoder().encode(key || "not-secret"), - { name: "HMAC", hash: "SHA-512" }, - false, - ["sign", "verify"], - ); -} - -export function createCookieSessionStorage(cookieOptions?: CookieOptions) { - let cookieOptionsParam = cookieOptions; - if (!cookieOptionsParam) { - cookieOptionsParam = {}; - } - - return CookieSessionStorage.init(cookieOptionsParam); -} - -export class CookieSessionStorage { - #key: CryptoKey; - #cookieOptions: CookieOptions; - - constructor(key: CryptoKey, cookieOptions: CookieOptions) { - this.#key = key; - this.#cookieOptions = cookieOptions; - } - - static async init(cookieOptions: CookieOptions) { - return new this(await key(), cookieOptions); - } - - create() { - return new Session(); - } - - exists(sessionId: string) { - return verify(sessionId, this.#key) - .then(() => true) - .catch((e) => { - console.warn("Invalid JWT token, creating new session..."); - return false; - }); - } - - get(sessionId: string) { - const [, payload] = decode(sessionId); - const { _flash = {}, ...data } = payload; - return new Session(data as object, _flash); - } - - async persist(response: Response, session: Session) { - if (session.doKeyRotate) { - this.keyRotate(); - } - - setCookie(response.headers, { - name: "sessionId", - value: await create( - { alg: "HS512", typ: "JWT" }, - { ...session.data, _flash: session.flashedData }, - this.#key, - ), - path: "/", - ...this.#cookieOptions, - }); - - return response; - } - /** - * Does not work in cookie sessions. - */ - keyRotate() { - console.warn( - "%c*****************************************************\n* '.keyRotate' is not supported for cookie sessions *\n*****************************************************", - "color: yellow;", - ); - } -} - -export function cookieSession(cookieOptions?: CookieOptions) { - return async function ( - req: Request, - ctx: MiddlewareHandlerContext, - ): Promise { - const { sessionId } = getCookies(req.headers); - const cookieSessionStorage = await createCookieSessionStorage( - cookieOptions, - ); - - if (sessionId && (await cookieSessionStorage.exists(sessionId))) { - ctx.state.session = await cookieSessionStorage.get(sessionId); - } - - if (!ctx.state.session) { - ctx.state.session = cookieSessionStorage.create(); - } - - const response = await ctx.next(); - - return cookieSessionStorage.persist(response, ctx.state.session); - }; -} diff --git a/src/stores/cookie_option.ts b/src/stores/cookie_option.ts deleted file mode 100644 index 31fab5e..0000000 --- a/src/stores/cookie_option.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { type Cookie } from "../deps.ts"; - -export type CookieOptions = Omit; -export type CookieWithRedisOptions = CookieOptions & { keyPrefix?: string }; diff --git a/src/stores/cookie_store.ts b/src/stores/cookie_store.ts new file mode 100644 index 0000000..08175e2 --- /dev/null +++ b/src/stores/cookie_store.ts @@ -0,0 +1,123 @@ +import { getSessionPayloadFromCookie } from "../utils/request.ts"; +import { createSession } from "../session.ts"; +import { jwtCreate, jwtVerify } from "../../deps.ts"; +import { + FlashData, + RequiredCookieOptions, + Session, + SessionData, + SessionDuplicationData, +} from "../type.ts"; +import { setSessionText } from "../utils/response.ts"; + +export function getCryptokey() { + const key = Deno.env.get("APP_SESSION_CRYPTO_KEY"); + + if (!key) { + console.warn( + "[FRESH SESSION] Warning: We didn't detect a env variable `APP_SESSION_CRYPTO_KEY`, if you are in production please fix this ASAP to avoid any security issue.", + ); + } + + return crypto.subtle.importKey( + "raw", + new TextEncoder().encode(key || "not-secret"), + { name: "HMAC", hash: "SHA-512" }, + false, + ["sign", "verify"], + ); +} + +async function sessionDataFromJwt( + src: string, + cryptoKey: CryptoKey, +): Promise<{ session: SessionData; flash: FlashData }> { + try { + const payload = await jwtVerify(src, cryptoKey); + const { session, flash } = payload; + return { session: session || {}, flash: flash || {} }; + } catch (e) { + console.log(e); + console.warn("Invalid JWT token, creating new session..."); + return { session: {}, flash: {} }; + } +} + +async function jwtFromSessionData( + rawPayload: { session: SessionData; flash: FlashData }, + cryptoKey: CryptoKey, +) { + return await jwtCreate({ alg: "HS512", typ: "JWT" }, rawPayload, cryptoKey); +} + +function rotateKey() { + console.warn( + "%c*****************************************************\n* '.keyRotate' is not supported for cookie sessions *\n*****************************************************", + "color: yellow;", + ); +} + +function getSessionCookieSetterFunction( + getDuplicateDataFunction: { (): SessionDuplicationData }, + cryptoKey: CryptoKey, +) { + return async function (res: Response, cookieOptions: RequiredCookieOptions) { + const { operations, ...rawPayload } = getDuplicateDataFunction(); + + const payload = await jwtFromSessionData(rawPayload, cryptoKey); + + if (operations.doRotateKey) { + rotateKey(); + } + + if (operations.doDestroy) { + return setSessionText(res, "", { ...cookieOptions, maxAge: 0 }); + } + + return setSessionText(res, payload, cookieOptions); + }; +} + +export async function getCookieSession( + req: Request, + cookieName: string, +): Promise< + { + session: Session; + sessionCookieSetter: { + ( + res: Response, + cookieOptions: RequiredCookieOptions, + ): Response | Promise; + }; + } +> { + const cryptoKey = await getCryptokey(); + + const sessionText = getSessionPayloadFromCookie(req, cookieName); + + if (!sessionText) { + const { session, getDuplicateDataFunction } = createSession({ + session: {}, + flash: {}, + }); + const sessionCookieSetter = getSessionCookieSetterFunction( + getDuplicateDataFunction, + cryptoKey, + ); + return { session, sessionCookieSetter }; + } + + const src = await sessionDataFromJwt(sessionText, cryptoKey); + const { session, getDuplicateDataFunction } = createSession(src); + + const sessionCookieSetter = getSessionCookieSetterFunction( + getDuplicateDataFunction, + cryptoKey, + ); + + return { + session, + sessionCookieSetter, + }; +} diff --git a/src/stores/deno_kv_store.ts b/src/stores/deno_kv_store.ts new file mode 100644 index 0000000..297a327 --- /dev/null +++ b/src/stores/deno_kv_store.ts @@ -0,0 +1,151 @@ +import { getSessionPayloadFromCookie } from "../utils/request.ts"; +import { createSession } from "../session.ts"; +import { + FlashData, + RequiredCookieOptions, + Session, + SessionData, + SessionDuplicationData, + SessionFromDenoKV, +} from "../type.ts"; +import { setSessionText } from "../utils/response.ts"; + +async function sessionDataFromDenoKv( + sessionKey: string, + baseKeyPath: string[], + client: Deno.Kv, +): Promise<{ session: SessionData; flash: FlashData }> { + const { ["value"]: payload } = await client.get([ + ...baseKeyPath, + sessionKey, + ]); + console.log("sessionKey", sessionKey); + console.log("payload", payload); + console.log( + await client.get([ + ...baseKeyPath, + sessionKey, + ]), + ); + + if (!payload) { + return { session: {}, flash: {} }; + } + + const { session, flash } = JSON.parse(payload); + + return { session: session || {}, flash: flash || {} }; +} + +async function jsonFromSessionData< + T extends string, + F extends string, +>(rawPayload: { session: SessionData; flash: FlashData }) { + return await JSON.stringify(rawPayload); +} + +function rotateKey(prefix: string) { + return createSessionKey(prefix); +} + +function getSessionCookieSetterFunction( + getDuplicateDataFunction: { (): SessionDuplicationData }, + sessionKey: string, + baseKeyPath: string[], + prefix: string, + client: Deno.Kv, +) { + return async function (res: Response, cookieOptions: RequiredCookieOptions) { + const { operations, ...rawPayload } = getDuplicateDataFunction(); + + const payload = await jsonFromSessionData(rawPayload); + + let newSessionKey = operations.doRotateKey ? rotateKey(prefix) : sessionKey; + newSessionKey = operations.doDestroy ? "" : newSessionKey; + const newCookieOptions = operations.doDestroy + ? { ...cookieOptions, maxAge: 0 } + : cookieOptions; + + if (operations.doRotateKey || operations.doDestroy) { + await client.delete([...baseKeyPath, sessionKey]); + } + + if (!operations.doDestroy) { + console.log(baseKeyPath); + console.log([...baseKeyPath, newSessionKey], payload, { + expireIn: cookieOptions.maxAge, + }); + + const RRRR = await client.set([...baseKeyPath, newSessionKey], payload, { + //expireIn: cookieOptions.maxAge * 1000, + }); + console.log("RRRR", RRRR); + console.log( + "RRRR", + await client.get([...baseKeyPath, sessionKey]), + ); + } + + return setSessionText(res, newSessionKey, newCookieOptions); + }; +} + +function createSessionKey(prefix: string): string { + return `${prefix}${crypto.randomUUID()}`; +} + +export async function getDenoKvSession( + req: Request, + cookieName: string, + baseKeyPath: string[], + keyPrefix: string, + client: Deno.Kv, +): Promise<{ + session: Session; + sessionCookieSetter: { + (res: Response, cookieOptions: RequiredCookieOptions): Response | Promise; + }; +}> { + console.log({ + req, + cookieName, + keyPrefix, + client, + }); + + const sessionKey = getSessionPayloadFromCookie(req, cookieName); + + if (!sessionKey) { + const { session, getDuplicateDataFunction } = createSession({ + session: {}, + flash: {}, + }); + + const newSessionKey = createSessionKey(keyPrefix); + + const sessionCookieSetter = getSessionCookieSetterFunction( + getDuplicateDataFunction, + newSessionKey, + baseKeyPath, + keyPrefix, + client, + ); + return { session, sessionCookieSetter }; + } + + const src = await sessionDataFromDenoKv(sessionKey, baseKeyPath, client); + const { session, getDuplicateDataFunction } = createSession(src); + + const sessionCookieSetter = getSessionCookieSetterFunction( + getDuplicateDataFunction, + sessionKey, + baseKeyPath, + keyPrefix, + client, + ); + + return { + session, + sessionCookieSetter, + }; +} diff --git a/src/stores/interface.ts b/src/stores/interface.ts deleted file mode 100644 index 290c083..0000000 --- a/src/stores/interface.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { MiddlewareHandlerContext } from "../deps.ts"; -import { Session } from "../session.ts"; -export type WithSession = { - session: Session; -}; - -export type sessionModule =(req: Request, ctx: MiddlewareHandlerContext) => Promise diff --git a/src/stores/kv.ts b/src/stores/kv.ts deleted file mode 100644 index fa1eb83..0000000 --- a/src/stores/kv.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { - deleteCookie, - getCookies, - MiddlewareHandlerContext, - setCookie, -} from "../deps.ts"; -import { type CookieOptions, CookieWithRedisOptions } from "./cookie_option.ts"; -import { Session } from "../session.ts"; -import type { WithSession } from "./interface.ts"; - -export function createKvSessionStorage( - sessionId: string, - store: Deno.Kv, - keyPrefix: string, - cookieOptions?: CookieOptions, -) { - let cookieOptionsParam = cookieOptions; - if (!cookieOptionsParam) { - cookieOptionsParam = {}; - } - - return KvSessionStorage.init( - sessionId, - store, - keyPrefix, - cookieOptionsParam, - ); -} - -export class KvSessionStorage { - #sessionKey: string; - #keyPrefix: string; - #store: Deno.Kv; - #cookieOptions: CookieOptions; - constructor( - key: string, - store: Deno.Kv, - keyPrefix: string, - cookieOptions: CookieOptions, - ) { - this.#sessionKey = key; - this.#store = store; - this.#keyPrefix = keyPrefix; - this.#cookieOptions = cookieOptions; - } - - static init( - sessionKey: string | undefined, - store: Deno.Kv, - keyPrefix: string, - cookieOptions: CookieOptions, - ) { - let key = !sessionKey ? crypto.randomUUID() : sessionKey; - - return new this(key, store, keyPrefix, cookieOptions); - } - - get key() { - return `${this.#keyPrefix}${this.#sessionKey}`; - } - - create() { - return new Session(); - } - - async exists(): Promise { - return !(await this.#store.get(["fresh-session", this.key]).value); - } - - async get() { - const { _flash = {}, data } = { - ...(await this.#store.get(["fresh-session", this.key])).value, - }; - - return new Session(data as object, _flash); - } - - async persist(response: Response, session: Session) { - if (session.doKeyRotate) { - this.keyRotate(); - } - - if (session.doDelete) { - await this.#store.delete(["fresh-session", this.key]); - - deleteCookie(response.headers, "sessionId"); - } else { - let redisOptions: { ex?: number } = {}; - - if (this.#cookieOptions?.maxAge) { - redisOptions.ex = this.#cookieOptions.maxAge; - } - if (this.#cookieOptions?.expires) { - redisOptions.ex = Math.round( - ((this.#cookieOptions?.expires).getTime() - new Date().getTime()) / - 1000, - ); - } - - await this.#store.set( - ["fresh-session", this.key], - { data: session.data, _flash: session.flashedData }, - redisOptions, - ); - - setCookie(response.headers, { - name: "sessionId", - value: this.#sessionKey, - path: "/", - ...this.#cookieOptions, - }); - } - - return response; - } - keyRotate() { - this.#sessionKey = crypto.randomUUID(); - } -} - -function hasKeyPrefix( - cookieWithRedisOptions: any, -): cookieWithRedisOptions is { keyPrefix: string } { - if (!cookieWithRedisOptions) return false; - if (typeof cookieWithRedisOptions !== "object") return false; - if (!cookieWithRedisOptions.keyPrefix) return false; - if (typeof cookieWithRedisOptions.keyPrefix !== "string") return false; - return true; -} - -export function kvSession( - storePath: string|null, - cookieWithRedisOptions?: CookieWithRedisOptions, -) { - let setupKeyPrefix = "session_"; - let setupCookieOptions = cookieWithRedisOptions; - - if (hasKeyPrefix(cookieWithRedisOptions)) { - const { keyPrefix, ...cookieOptions } = cookieWithRedisOptions; - setupKeyPrefix = keyPrefix; - setupCookieOptions = cookieOptions; - } - - return async function ( - req: Request, - ctx: MiddlewareHandlerContext, - ) { - const { sessionId } = getCookies(req.headers); - - const kvStore = await Deno.openKv(storePath); - const kvSessionStorage = await createKvSessionStorage( - sessionId, - kvStore, - setupKeyPrefix, - setupCookieOptions, - ); - - if (sessionId && (await kvSessionStorage.exists())) { - ctx.state.session = await kvSessionStorage.get(); - } - - if (!ctx.state.session) { - ctx.state.session = kvSessionStorage.create(); - } - const response = await ctx.next(); - - const persistedResponse = await kvSessionStorage.persist( - response, - ctx.state.session, - ); - - await kvStore.close(); - - return persistedResponse; - }; -} diff --git a/src/stores/redis.ts b/src/stores/redis.ts deleted file mode 100644 index 9c959a6..0000000 --- a/src/stores/redis.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { - deleteCookie, - getCookies, - MiddlewareHandlerContext, - setCookie, -} from "../deps.ts"; -import { type CookieOptions, CookieWithRedisOptions } from "./cookie_option.ts"; -import { Session } from "../session.ts"; -import type { WithSession } from "./interface.ts"; - -export interface Store { - set: Function; - get: Function; - del: Function; -} - -export function createRedisSessionStorage( - sessionId: string, - store: Store, - keyPrefix: string, - cookieOptions?: CookieOptions, -) { - let cookieOptionsParam = cookieOptions; - if (!cookieOptionsParam) { - cookieOptionsParam = {}; - } - - return RedisSessionStorage.init( - sessionId, - store, - keyPrefix, - cookieOptionsParam, - ); -} - -export class RedisSessionStorage { - #sessionKey: string; - #keyPrefix: string; - #store: Store; - #cookieOptions: CookieOptions; - constructor( - key: string, - store: Store, - keyPrefix: string, - cookieOptions: CookieOptions, - ) { - this.#sessionKey = key; - this.#store = store; - this.#keyPrefix = keyPrefix; - this.#cookieOptions = cookieOptions; - } - - static init( - sessionKey: string | undefined, - store: Store, - keyPrefix: string, - cookieOptions: CookieOptions, - ) { - let key = !sessionKey ? crypto.randomUUID() : sessionKey; - - return new this(key, store, keyPrefix, cookieOptions); - } - - get key() { - return `${this.#keyPrefix}${this.#sessionKey}`; - } - - create() { - return new Session(); - } - - async exists(): Promise { - return !!(await this.#store.get(this.key)); - } - - async get() { - const { _flash = {}, data } = JSON.parse(await this.#store.get(this.key)); - return new Session(data as object, _flash); - } - - async persist(response: Response, session: Session) { - if (session.doKeyRotate) { - this.keyRotate(); - } - - if (session.doDelete) { - await this.#store.del(this.key); - - deleteCookie(response.headers, "sessionId"); - } else { - let redisOptions: { ex?: number } = {}; - - if (this.#cookieOptions?.maxAge) { - redisOptions.ex = this.#cookieOptions.maxAge; - } - if (this.#cookieOptions?.expires) { - redisOptions.ex = Math.round( - ((this.#cookieOptions?.expires).getTime() - new Date().getTime()) / - 1000, - ); - } - - await this.#store.set( - this.key, - JSON.stringify({ data: session.data, _flash: session.flashedData }), - redisOptions, - ); - - setCookie(response.headers, { - name: "sessionId", - value: this.#sessionKey, - path: "/", - ...this.#cookieOptions, - }); - } - - return response; - } - keyRotate() { - this.#sessionKey = crypto.randomUUID(); - } -} - -function hasKeyPrefix( - cookieWithRedisOptions: any, -): cookieWithRedisOptions is { keyPrefix: string } { - if (!cookieWithRedisOptions) return false; - if (typeof cookieWithRedisOptions !== "object") return false; - if (!cookieWithRedisOptions.keyPrefix) return false; - if (typeof cookieWithRedisOptions.keyPrefix !== "string") return false; - return true; -} - -export function redisSession( - store: Store, - cookieWithRedisOptions?: CookieWithRedisOptions, -) { - const redisStore = store; - - let setupKeyPrefix = "session_"; - let setupCookieOptions = cookieWithRedisOptions; - - if (hasKeyPrefix(cookieWithRedisOptions)) { - const { keyPrefix, ...cookieOptions } = cookieWithRedisOptions; - setupKeyPrefix = keyPrefix; - setupCookieOptions = cookieOptions; - } - - return async function ( - req: Request, - ctx: MiddlewareHandlerContext, - ) { - const { sessionId } = getCookies(req.headers); - const redisSessionStorage = await createRedisSessionStorage( - sessionId, - redisStore, - setupKeyPrefix, - setupCookieOptions, - ); - - if (sessionId && (await redisSessionStorage.exists())) { - ctx.state.session = await redisSessionStorage.get(); - } - - if (!ctx.state.session) { - ctx.state.session = redisSessionStorage.create(); - } - const response = await ctx.next(); - - return redisSessionStorage.persist(response, ctx.state.session); - }; -} diff --git a/src/stores/redis_store.ts b/src/stores/redis_store.ts new file mode 100644 index 0000000..9d743bf --- /dev/null +++ b/src/stores/redis_store.ts @@ -0,0 +1,120 @@ +import { getSessionPayloadFromCookie } from "../utils/request.ts"; +import { createSession } from "../session.ts"; +import { + FlashData, + RedisClient, + RequiredCookieOptions, + Session, + SessionData, + SessionDuplicationData, +} from "../type.ts"; +import { setSessionText } from "../utils/response.ts"; + +async function sessionDataFromRedis( + sessionKey: string, + client: RedisClient, +): Promise<{ session: SessionData; flash: FlashData }> { + const payload = await client.get(sessionKey); + + if (!payload) { + return { session: {}, flash: {} }; + } + + const { session, flash } = JSON.parse(payload); + + return { session: session || {}, flash: flash || {} }; +} + +async function jsonFromSessionData( + rawPayload: { session: SessionData; flash: FlashData }, +) { + return await JSON.stringify(rawPayload); +} + +function rotateKey(prefix: string) { + return createSessionKey(prefix); +} + +function getSessionCookieSetterFunction( + getDuplicateDataFunction: { (): SessionDuplicationData }, + sessionKey: string, + prefix: string, + client: RedisClient, +) { + return async function (res: Response, cookieOptions: RequiredCookieOptions) { + const { operations, ...rawPayload } = getDuplicateDataFunction(); + + const payload = await jsonFromSessionData(rawPayload); + + let newSessionKey = operations.doRotateKey ? rotateKey(prefix) : sessionKey; + newSessionKey = operations.doDestroy ? "" : newSessionKey; + const newCookieOptions = operations.doDestroy + ? { ...cookieOptions, maxAge: 0 } + : cookieOptions; + + if (operations.doRotateKey || operations.doDestroy) { + await client.del(sessionKey); + } + + if (!operations.doDestroy) { + await client.set(newSessionKey, payload, { ex: cookieOptions.maxAge }); + } + + return setSessionText(res, newSessionKey, newCookieOptions); + }; +} + +function createSessionKey(prefix: string): string { + return `${prefix}${crypto.randomUUID()}`; +} + +export async function getRedisSession( + req: Request, + cookieName: string, + keyPrefix: string, + client: RedisClient, +): Promise< + { + session: Session; + sessionCookieSetter: { + ( + res: Response, + cookieOptions: RequiredCookieOptions, + ): Response | Promise; + }; + } +> { + const sessionKey = getSessionPayloadFromCookie(req, cookieName); + + if (!sessionKey) { + const { session, getDuplicateDataFunction } = createSession({ + session: {}, + flash: {}, + }); + + const newSessionKey = createSessionKey(keyPrefix); + + const sessionCookieSetter = getSessionCookieSetterFunction( + getDuplicateDataFunction, + newSessionKey, + keyPrefix, + client, + ); + return { session, sessionCookieSetter }; + } + + const src = await sessionDataFromRedis(sessionKey, client); + const { session, getDuplicateDataFunction } = createSession(src); + + const sessionCookieSetter = getSessionCookieSetterFunction( + getDuplicateDataFunction, + sessionKey, + keyPrefix, + client, + ); + + return { + session, + sessionCookieSetter, + }; +} diff --git a/src/type.ts b/src/type.ts new file mode 100644 index 0000000..9f75d0f --- /dev/null +++ b/src/type.ts @@ -0,0 +1,101 @@ +import { type Cookie } from "../deps.ts"; + +export type AllowType = object | string | number | boolean; +export type SessionData = { + [key in T]?: AllowType; +}; + +export type FlashData = { + [key in F]?: AllowType; +}; + +export type SessionOperations = { + doDestroy: boolean; + doRotateKey: boolean; +}; + +export type SessionDuplicationData = { + session: SessionData; + flash: FlashData; + operations: SessionOperations; +}; + +export interface SessionFromDenoKV { + session: SessionData; + flash: FlashData; +} + +export type Session = { + get: { (key: T): SessionData[T] }; + set: { (key: T, value: AllowType): void }; + delete: { (key: T): void }; + list: { (): SessionData }; + destroy: { (): void }; + rotateKey: { (): void }; + has: { (key: T): boolean }; + clear: { (): void }; + flash: { (key: F): FlashData[F]; (key: F, value: AllowType): void }; + flashNow: { (key: F): AllowType }; + getRawData: { (): SessionDuplicationData }; +}; + +export type CookieOptions = Omit< + Cookie, + "value" | "expires" | "name" | "unparsed" +>; +export type PartialCookieOptions = Partial; +export type RequiredCookieOptions = Required; + +// NOTE: USAGE: HandlerContext> +export type WithSession = { + session: Session; +}; + +export interface FreshSessionBaseOptions { + cookieOptions?: PartialCookieOptions; + excludePath?: string[]; +} + +export type CookieFreshSessionOptions = FreshSessionBaseOptions + +export interface RequiredCookieFreshSessionOptions + extends Required { + cookieOptions: RequiredCookieOptions; +} + +interface redisSetOptions { + ex?: number; +} + +export interface RedisClient { + set: { + ( + key: string, + value: string, + redisOptions: redisSetOptions, + ): Promise | void; + }; + get: { (key: string): Promise }; + del: { (key: string): Promise | void }; +} + +export interface RedisFreshSessionOptions extends FreshSessionBaseOptions { + client: RedisClient; + keyPrefix?: string; +} + +export interface RequiredRedisFreshSessionOptions + extends Required { + cookieOptions: RequiredCookieOptions; +} + +export interface DenoKvFreshSessionOptions extends FreshSessionBaseOptions { + client: Deno.Kv; + keyPrefix?: string; + baseKeyPath?: string[]; +} + +export interface RequiredDenoKvFreshSessionOptions + extends Required { + cookieOptions: RequiredCookieOptions; +} diff --git a/src/utils/request.ts b/src/utils/request.ts new file mode 100644 index 0000000..474cb7e --- /dev/null +++ b/src/utils/request.ts @@ -0,0 +1,13 @@ +import { getCookies } from "../../deps.ts"; +//export function getSessionText(req: Request): string | null { +// const { sessionText } = getCookies(req.headers); +// return sessionText; +//} + +export function getSessionPayloadFromCookie( + req: Request, + cookieName: string, +): string | null { + const { [cookieName]: sessionPayload } = getCookies(req.headers); + return sessionPayload; +} diff --git a/src/utils/response.ts b/src/utils/response.ts new file mode 100644 index 0000000..d88ce04 --- /dev/null +++ b/src/utils/response.ts @@ -0,0 +1,14 @@ +import { setCookie } from "../../deps.ts"; +import { RequiredCookieOptions } from "../type.ts"; +export function setSessionText( + res: Response, + payload: string, + cookieOptions: RequiredCookieOptions, +): Response { + setCookie(res.headers, { + value: payload, + ...cookieOptions, + }); + + return res; +} diff --git a/tests/1_dashboard_test.js b/tests/1_dashboard_test.js deleted file mode 100644 index bf74a27..0000000 --- a/tests/1_dashboard_test.js +++ /dev/null @@ -1,52 +0,0 @@ -import { BASE_URL, fixtureTestWrapper } from "./wrapper.js"; -import { assert, assertEquals } from "$std/assert/mod.ts"; -import { Status } from "$std/http/http_status.ts"; -import { wrapFetch } from "cookiejar"; - -const fetch = wrapFetch(); - -Deno.test( - "The Dashboard should show a new login", - { - sanitizeResources: false, - sanitizeOps: false, - }, - fixtureTestWrapper(async (t) => { - const EMAIL = "example@example.com"; - - await t.step("The dashboard shows nothing", async () => { - const response = await fetch(`${BASE_URL}/dashboard`); - assertEquals(response.status, Status.OK); - const text = await response.text(); - assert(!text.includes("
Flashed message: test
")); - }); - - await t.step("Post index page with 'email' form data.", async () => { - const body = new FormData(); - body.append("email", EMAIL); - const response = await fetch(`${BASE_URL}`, { - method: "POST", - body, - }); - const text = await response.text(); - assert( - text.includes( - `
  • email: ${EMAIL}
  • `, - ), - ); - assertEquals(response.status, Status.OK); - }); - - await t.step("The dashboard shows the login", async () => { - const response = await fetch(`${BASE_URL}/dashboard`); - const text = await response.text(); - console.log(text); - assert( - text.includes( - `You are logged in as ${EMAIL}`, - ), - ); - assertEquals(response.status, Status.OK); - }); - }), -); diff --git a/tests/2_route_test.js b/tests/2_route_test.js deleted file mode 100644 index ff16500..0000000 --- a/tests/2_route_test.js +++ /dev/null @@ -1,68 +0,0 @@ -import { BASE_URL, fixtureTestWrapper } from "./wrapper.js"; -import { assert, assertEquals } from "$std/assert/mod.ts"; -import { Status } from "$std/http/http_status.ts"; -import { wrapFetch } from "cookiejar"; - -const fetch = wrapFetch(); - -Deno.test( - "Route Testing", - { - sanitizeResources: false, - sanitizeOps: false, - }, - fixtureTestWrapper(async (t) => { - await t.step("The index page should work", async () => { - const response = await fetch(`${BASE_URL}`); - assertEquals(response.status, Status.OK); - const text = await response.text(); - assert(!text.includes("
    Flashed message: test
    ")); - }); - - await t.step("Post index page with 'email' form data.", async () => { - const form_data = new FormData(); - form_data.append("email", "taylor@example.com"); - const response = await fetch(`${BASE_URL}`, { - method: "POST", - body: form_data, - credentials: "include", - }); - const text = await response.text(); - assert( - text.includes( - "
    Flashed message: Successfully "logged in"
    ", - ), - ); - assertEquals(response.status, Status.OK); - }); - - await t.step("The dashboard should work", async () => { - const response = await fetch(`${BASE_URL}/dashboard`); - assertEquals(response.status, Status.OK); - }); - - await t.step("The other route should work", async () => { - const response = await fetch(`${BASE_URL}/other-route`, { - method: "POST", - }); - const text = await response.text(); - // console.log(text); - assert( - text.includes( - "
    Flashed message: test
    ", - ), - ); - assert( - text.includes( - "
    Flashed message: [{"msg":"test 2"}]
    ", - ), - ); - assertEquals(response.status, Status.OK); - }); - - await t.step("The 404 page should 404", async () => { - const response = await fetch(`${BASE_URL}/404`); - assertEquals(response.status, Status.NotFound); - }); - }), -); diff --git a/tests/3_kvStore_test.js b/tests/3_kvStore_test.js deleted file mode 100644 index 8f9ed8f..0000000 --- a/tests/3_kvStore_test.js +++ /dev/null @@ -1,84 +0,0 @@ -import { BASE_URL, exampleKVStoreTestWrapper } from "./wrapper.js"; -import { assert, assertEquals } from "$std/assert/mod.ts"; -import { Status } from "$std/http/http_status.ts"; -import { wrapFetch } from "cookiejar"; - -const fetch = wrapFetch(); - -Deno.test( - "Test KV Store Example", - { - sanitizeResources: false, - sanitizeOps: false, - }, - exampleKVStoreTestWrapper(async (t) => { - await t.step("The index page should work", async () => { - const response = await fetch(`${BASE_URL}`); - assertEquals(response.status, Status.OK); - const text = await response.text(); - assert(text.includes("
    Flash Message:
    ")); - // console.log(text); - }); - - const SESSION_TEXT = "This is some _Session Text_"; - await t.step( - "Post index page with 'new_session_text_value' form data.", - async () => { - const form_data = new FormData(); - form_data.append("new_session_text_value", SESSION_TEXT); - const response = await fetch(`${BASE_URL}`, { - method: "POST", - body: form_data, - }); - const text = await response.text(); - // console.log(text); - assert( - text.includes("
    Flash Message: Session value update!
    "), - ); - assert(text.includes(`
    Now Session Value: ${SESSION_TEXT}
    `)); - assertEquals(response.status, Status.OK); - }, - ); - - await t.step("Visit again to verify session value", async () => { - const response = await fetch(`${BASE_URL}`); - const text = await response.text(); - assert( - text.includes("
    Flash Message:
    "), - ); - assert(text.includes(`
    Now Session Value: ${SESSION_TEXT}
    `)); - assertEquals(response.status, Status.OK); - }); - - await t.step("Delete the session value", async () => { - const body = new FormData(); - body.append("method", "DELETE"); - const response = await fetch(`${BASE_URL}`, { - method: "POST", - body, - }); - const text = await response.text(); - assert( - text.includes("
    Flash Message: Delete value!
    "), - ); - assert(text.includes(`
    Now Session Value:
    `)); - assertEquals(response.status, Status.OK); - }); - - await t.step("Visit again to verify session value is gone", async () => { - const response = await fetch(`${BASE_URL}`); - const text = await response.text(); - assert( - text.includes( - "
    Flash Message:
    Now Session Value:
    ", - ), - ); - assertEquals(response.status, Status.OK); - }); - - await t.step("The 404 page should 404", async () => { - const response = await fetch(`${BASE_URL}/404`); - assertEquals(response.status, Status.NotFound); - }); - }), -); diff --git a/tests/config/cookie_session_test_plugin_fresh.config.ts b/tests/config/cookie_session_test_plugin_fresh.config.ts new file mode 100644 index 0000000..37aaaac --- /dev/null +++ b/tests/config/cookie_session_test_plugin_fresh.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "$fresh/server.ts"; +import { getCookieSessionPlugin } from "../../mod.ts"; +import { testPlugin } from "../plugin/test_plugin.ts"; + +export default defineConfig({ + plugins: [getCookieSessionPlugin("/"), testPlugin], +}); diff --git a/tests/config/redis_session_test_plugin_fresh.config.ts b/tests/config/redis_session_test_plugin_fresh.config.ts new file mode 100644 index 0000000..928427e --- /dev/null +++ b/tests/config/redis_session_test_plugin_fresh.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "$fresh/server.ts"; +import { getRedisSessionPlugin } from "../../mod.ts"; +import { testPlugin } from "../plugin/test_plugin.ts"; +import Redis from 'https://unpkg.com/ioredis-mock'; +const redis = new Redis() + +export default defineConfig({ + plugins: [getRedisSessionPlugin("/", {client: redis}), testPlugin], +}); diff --git a/tests/cookie_session_test.ts b/tests/cookie_session_test.ts new file mode 100644 index 0000000..0587e05 --- /dev/null +++ b/tests/cookie_session_test.ts @@ -0,0 +1,45 @@ +import { createHandler, ServeHandlerInfo } from "https://deno.land/x/fresh@1.5.4/server.ts"; +import manifest from "./work/fresh.gen.ts"; +import config from "./config/cookie_session_test_plugin_fresh.config.ts"; +import { assert, assertEquals } from "$std/testing/asserts.ts"; + +const CONN_INFO: ServeHandlerInfo = { + remoteAddr: { hostname: "127.0.0.1", port: 53496, transport: "tcp" }, +}; + +Deno.test("Cookie Session Test", async (t) => { + const handler = await createHandler(manifest, config); + + await t.step("#1 GET /", async () => { + let resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + assertEquals(resp.status, 200); + + let text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + + const sessionKey = (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; + + resp = await handler(new Request("http://127.0.0.1/session", {headers: {cookie: `session=${sessionKey}`}}), CONN_INFO); + assertEquals(resp.status, 200); + text = await resp.text(); + assertEquals(text.includes("

    count:1

    "), true); + + }); + +// await t.step("#2 POST /", async () => { +// const formData = new FormData(); +// formData.append("text", "Deno!"); +// const req = new Request("http://127.0.0.1/", { +// method: "POST", +// body: formData, +// }); +// const resp = await handler(req, CONN_INFO); +// assertEquals(resp.status, 303); +// }); +// +// await t.step("#3 GET /foo", async () => { +// const resp = await handler(new Request("http://127.0.0.1/foo"), CONN_INFO); +// const text = await resp.text(); +// assert(text.includes("
    Hello Foo!
    ")); +// }); +}); diff --git a/tests/fixture/deno.json b/tests/fixture/deno.json deleted file mode 100644 index 00adb91..0000000 --- a/tests/fixture/deno.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "tasks": { - "start": "deno run -A --watch=static/,routes/ dev.ts" - }, - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "preact" - }, - "imports": { - "$fresh/": "https://deno.land/x/fresh@1.3.1/", - "preact": "https://esm.sh/preact@10.15.1", - "preact/": "https://esm.sh/preact@10.15.1/", - "preact-render-to-string": "https://esm.sh/preact-render-to-string@6.1.0", - "fresh-session": "../../mod.ts" - }, - "lock": false -} diff --git a/tests/fixture/dev.ts b/tests/fixture/dev.ts deleted file mode 100755 index 918c2eb..0000000 --- a/tests/fixture/dev.ts +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env -S deno run -A --watch=static/,routes/ - -Deno.env.set("APP_KEY", "not-secret"); - -import dev from "$fresh/dev.ts"; - -await dev(import.meta.url, "./main.ts"); diff --git a/tests/fixture/fresh.gen.ts b/tests/fixture/fresh.gen.ts deleted file mode 100644 index 28c5351..0000000 --- a/tests/fixture/fresh.gen.ts +++ /dev/null @@ -1,21 +0,0 @@ -// DO NOT EDIT. This file is generated by fresh. -// This file SHOULD be checked into source version control. -// This file is automatically updated during development when running `dev.ts`. - -import * as $0 from "./routes/_middleware.ts"; -import * as $1 from "./routes/dashboard/index.tsx"; -import * as $2 from "./routes/index.tsx"; -import * as $3 from "./routes/other-route.tsx"; - -const manifest = { - routes: { - "./routes/_middleware.ts": $0, - "./routes/dashboard/index.tsx": $1, - "./routes/index.tsx": $2, - "./routes/other-route.tsx": $3, - }, - islands: {}, - baseUrl: import.meta.url, -}; - -export default manifest; diff --git a/tests/fixture/main.ts b/tests/fixture/main.ts deleted file mode 100644 index bae9199..0000000 --- a/tests/fixture/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -/// -/// -/// -/// -/// - -import { start } from "$fresh/server.ts"; -import manifest from "./fresh.gen.ts"; -await start(manifest); diff --git a/tests/fixture/routes/_middleware.ts b/tests/fixture/routes/_middleware.ts deleted file mode 100644 index 7bb876e..0000000 --- a/tests/fixture/routes/_middleware.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { cookieSession } from "fresh-session"; - -export const handler = cookieSession(); diff --git a/tests/fixture/routes/dashboard/index.tsx b/tests/fixture/routes/dashboard/index.tsx deleted file mode 100644 index 88ec000..0000000 --- a/tests/fixture/routes/dashboard/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Handlers, PageProps } from "$fresh/server.ts"; -import { WithSession } from "fresh-session"; - -export type Data = { session: Record }; - -export const handler: Handlers< - Data, - WithSession // indicate with Typescript that the session is in the `ctx.state` -> = { - GET(_req, ctx) { - // The session is accessible via the `ctx.state` - const { session } = ctx.state; - - // You can pass the session data to the page - return ctx.render({ session: session.data }); - }, -}; - -export default function Dashboard({ data }: PageProps) { - return
    You are logged in as {data.session.email}
    ; -} diff --git a/tests/fixture/routes/index.tsx b/tests/fixture/routes/index.tsx deleted file mode 100644 index ad3de9c..0000000 --- a/tests/fixture/routes/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { Handlers, PageProps } from "$fresh/server.ts"; -import type { WithSession } from "fresh-session"; - -export type Data = { - session: Record; - flashedMessage?: string; - msg?: string; - errors?: any[]; -}; - -export const handler: Handlers< - Data, - WithSession -> = { - GET(_req, ctx) { - const { session } = ctx.state; - - const flashedMessage = ctx.state.session.flash("success"); - const msg = ctx.state.session.get("msg"); - const errors = ctx.state.session.flash("errors"); - - return ctx.render({ session: session.data, flashedMessage, msg, errors }); - }, - - async POST(req, ctx) { - const formData = await req.formData(); - - // ctx.state.session.data = { - // email: formData.get("email"), - // }; - ctx.state.session.set("email", formData.get("email")); - ctx.state.session.flash("success", 'Successfully "logged in"'); - - return new Response(null, { - status: 303, - headers: { - "Location": "/", - }, - }); - }, -}; - -export default function Home({ data }: PageProps) { - return ( -
    - {!!data.flashedMessage && ( -
    - Flashed message: {data.flashedMessage} -
    - )} - - {!!data.msg && ( -
    - Flashed message: {data.msg} -
    - )} - - {!!data.errors && ( -
    - Flashed message: {JSON.stringify(data.errors)} -
    - )} - -
    -

    Your session data

    - -
      - {Object.entries(data.session).map(([key, value]) => { - return
    • {key}: {value}
    • ; - })} -
    -
    - -
    -
    - - - -
    -
    - -
    -
    - -
    -
    -
    - ); -} diff --git a/tests/fixture/routes/other-route.tsx b/tests/fixture/routes/other-route.tsx deleted file mode 100644 index f48c3dd..0000000 --- a/tests/fixture/routes/other-route.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Handlers } from "$fresh/server.ts"; -import { WithSession } from "fresh-session"; - -export const handler: Handlers = { - POST(_req, ctx) { - ctx.state.session.set("msg", "test"); - ctx.state.session.flash("errors", [{ msg: "test 2" }]); - - return new Response(null, { status: 303, headers: { "Location": "/" } }); - }, -}; diff --git a/tests/fixture/static/favicon.ico b/tests/fixture/static/favicon.ico deleted file mode 100644 index 1cfaaa2193b0f210107a559f7421569f57a25388..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22382 zcmeI4dw7?{mB%N97z7oqA|OH{6p11r>cU#lM7K(nW`t#!NG z`qUAy{#t>9K|!BwH6TqGo5?%XehL;`0&-}m=Ue0llhcL@pl$8VmT z%zK+TmpOCh%*>geb9pY`9euPTFLpO|c5Z}ouDCdHKbPk-c~(}IxG%ZDxr=%@SHd^E zqD103nR9%XEERoVu3rrLu0HUY|1MgG%1x{{_pcwC`)FSxKQUHUyl&n5r0WaUnLDS_ zO1@EJ-yc$bGez?bM z=RUI!pyBE&vtsb~Nlt_6nbdbp$ix3y;iH@E#h>mpJEOtu-!_}g;rgj-#Y+6IA}J3UgmtZ|>|08$6-G-YTPxu6$cc zJ}Rv5v(Pi0IwV{0`8sY^c>!W~<7>=~Tx&xf*kG?*vC-^u@LmTG`5`^sYZLs?&Z47< zau=(tlCR@3bgovaC9=>IxZ5Az`p`7QbsLpKRZnMv?v+|=>T0dXj*Kq-QIJBHP z|7e}QxX#YKtKQ~J++@|)ZM40&Ldy@fo4v5p8sT>e-{eKhtBxXMsXo$eWkM!yf#sjQ z)=I9cwrlAl)9$Ue??K~b`75l;@nQc`xp-2&f?j+x6#e{Gt+~pN%r!Kd8&_?vC(rv! ze}Ht!_gP;j?HADK%gukuxzat@j{@hWVjre<;!Qq~$8`v0%_HeUVb!WU|dRvpYNRdVE0va2Ds}tG@I?%%a~DZ z+u;ANyx$6VJD+L3fikD4Zsd}Z1bxF8E4%;Tv)D7AWShaCDZco3qWL`4-3NQ6JX!L# z2>aLL3+wIesy!aN+3%o*_wjnOxnB(4A;K+4CI|nHcE0+djrP&U*v&M4mmWAyW`kef zz77<7JW(0QR;%5+uC(JAkN>i~F^WBL{Ul@l$&8Ol#`|pOm;?U(d?e8!{3VQSyu0lu zn+#9If`7ZYLIqor{0{UZprMU)G=k$RaT(~I@y`t|x9P9#O8825gX?_8`YRdhr_uf| zB9mJBLOCrXzvZHJ37u#I9gD!%T{vaS0{+PdAp>-5;#}}91;>&2De{-Re^AK%5d4cb z@ZpryH)k^L{|j`;?-5XECh!lwyHNNA9>1=ST4lrWb?V;-zx*PPyCsL7Teh100YBwG z@ZZ)$Lk+t5U&!f4(UXUhWX$L#^pGEF9(hHouNT}5kqHs3>k-OExcn zdoS&PAEWv6LU13Ej`wK01hhhfWN|U`NqoW~rpIwLUuUYkFY^z*&!tbF1QH%q;{WbhR$6z5Te#G@DZsd`&W)Mv z+#sN5nRDG1C7^)3fcrx7{Mo>B0N>}=0XupA5%2d-bp`ttxk5YLb+?tSo7K9W)>L^T z-u$d6POXPhmzxS`9W_X0i7fX&CxM&fK@;>uo2i2g4Xk^fcJq# zz%1Y{pcLo>+zc!Ob^yD98ej&XcL9A-n%na_(w5i5>n`n4|A9I2>&(wtx3EFw!TQ6G z!!{Dnqkw6E_|RU7_MRoHwt)Cu4T$Gt<$uldjP_yLA`|KkWJ_L5yRTp$IM_Gv^9TH7d(H+5m#AY8&`~LM()|s}j?h{Y1vNjajf>d;N)H~_g2=U+EGVpbhkEVThJ<6I} zvb2_cjen{*U@f?#_>I>qyKp<>qxOc|RR*drT;FA^klo=-fGVuB7z1b#gg zyLT)59Q%Hs#O_69@djfd>$LIxkYsdr{{BkkIF`|1nLK$0vXJOkFMe+8yyIFFQDK5g4hWoMl`F$P!Pm% z27A??tUZ)pbe;G)rY>_G2>Cx1`&V}-`)qqs*!)z2S&Tg-)+vbn)VP2=y>1@LT(Ml5 zYi6tiA^#UbZ=?1gqp2Lo^Vm0pM-G6fZEPY;aC7WsZxTv&0`~u%-en6~Q;2#`f zIqZX<+r?9V;!`t8A^&C2xob9j`cwn&=Q75}_kk6w;P=dLz)sG>7gn4?)K_RkFtUxr z9JIu696~uLM(kMerSTwL3i&@7pQl>%`lS8-Wbp`bc_>yx`_yBZ7r%=fqDlIp7_dpy z>*IP3fgBW@H74XM9sAz)A5NcLpja&Jb1TiGKgZ)z;=J#7&l-W^I%E&yNpe_*9PTED zf!MG^;Wy9dpW!~S_kC!W37YRdAKL#n>Ep)`gRmcuv~{Zc6VZc}p$@!5`9Hz4{3M@b zTVJEUd=2{`Tpc)O{+;&kAstAUyq=Kvm*2104$W^AlT$`KRw{nu@6;FOz~3rlFch8d z2A`MHFJ49th@&N`{-?30oCyhJ&;flybL6wdn|!-;$;$vbCaYb1%Qu zPLeUe^O|kmhyI}$P{r~1q)V-*5OWgn-j2HPP|&U!w7&$@`<)g)_-gv)?(d+#>bn2U zI1t2;rs@0H$YLZi{XO+Y)j@VwYpX-b+s!`C#t#nG)YB>e9|W>OS6KfmqzxWdjPgAC zsAQlR-fZ~G8}T>Rpl3b_*CKR5>u$1*2dN9s!&8Cy$~3jefVF-4!IF^`i5O7% zdKbs~bS6Az@{Qv9o@T6#h#}~E#8De()(&QjSism;sPQe+R20VbhjKU%8B|@uS^(#g z0-K&m9B(E($G?#-+=ebx(Fc5zKRJhI8N>j$W;0)g_b%D+FF6IgD>e_i!SyxBU>mV_ z)<6R-K@KIfOPv1px<4Dc@CsvPG%1dLG;IJKt?}8~^B1B2F!7UZ@_PWtPWIzY*+b&l zZ4>RIc-=v*$Ux)2Y-JG7+D3b+c;BB87aR4Pbl&o-)R(0_cpBP+HR5df*Y}c}fc@Cc z;GG0C>3pQl3oJ$tPG@{b*6zKaUuPN>Uwk1pLq611tfN1G4eibNm#j?undB$iSQi;5 z>%pryaA?X@4v%>r+QNTS2GnyH{7*&?8a2n)nI8Fg;w#pRi1(QBO-UW_b#lJ9&UGKZE_p#9e?1KKn6e_G=|st3qG z{pkj5QG?D={fU06q%%G8aietWjKNfVy=77YlEzS7-%md{Joat0T(WD~T-hC;6a&t= zj#Oi#V&l&g|Lv6mSyEqkX8sanu#$7T_H%T4JM?H>=(Hp@LG67HJdfa=)=hNgLv}J5 zpQ)bdEQZD(pLAa6^49mDGM@isBOfn=Fds@^n9qJ$V3*cG+d6F21ngF}^X621N8kN3 z<6|W_d|HCcTUmd90vg+F`%}pzh|iIKfGz+%u!}#GP0;zVKeBe9wJ+JeOY!A()+|bY zdt7T=Q4E4lkAMd{;&6-TqrawNrOodogOGpWP>jzN^oMsfXW$IHtwk4P`{vO;I{T-y zM(x47>X4oJbHqnl4=(-o0d3%AptzbKK7zJsGmq&C7FT>MgHRR&z&9N^?9katonPCE zu4)}+EnJ_h&_oW%@wrf4jlr;qXhdP>3C?5_u?H|624MmKl)3^;8pZu zug>WxZfF`C3u^mmFjRkh$8v4p59;&>nF*JNiCq7eX5P z(I@U_U2z4!Wnqe?(s-%)q|$bTq4|!^s7e;maYJh)W6_nf7&ql(>KyG?xPLX`2dEBy zFC#b)7WV%+;0j9FTVn&qx%oiClr@+E;3V$3T2m5Zafg2!6iTF zIGBzUQb1p*pOI_LtBQe3(2Gg*k!O&{n?NPk8+o=J*a_&jGwOi9!}nZdC%#XN)RWO# ze@F6{P2KX%qO?b@U%1Iz6ft&<#639s)CxM&8D($iiPS z`4rnXm5kiNe6McZI7{TiY+rES)A(%zQnxTa()hgt(qXnS$U7Oofk4We!fz);a7v(y&DRt~7zy75O|tmn&+X8hls8Z!IVlSy`CR4)Ri4 z8s>?LhlK=}8ow<`Dm8wnA;=RIjN=zlbx%G+IRXhdGgifPzmOU3B69BS4)IC8#<@<) bck@HGWY%2idMme??%p8ZW3z(%VE+9-Ofn0d diff --git a/tests/fixture/static/logo.svg b/tests/fixture/static/logo.svg deleted file mode 100644 index ef2fbe4..0000000 --- a/tests/fixture/static/logo.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/tests/plugin/test_plugin.ts b/tests/plugin/test_plugin.ts new file mode 100644 index 0000000..b23c124 --- /dev/null +++ b/tests/plugin/test_plugin.ts @@ -0,0 +1,16 @@ + +import { Plugin, PageProps } from "https://deno.land/x/fresh@1.5.4/server.ts"; +import TestComponent from "../routes/session_test_route.tsx"; +import { ComponentType } from "https://esm.sh/preact@10.18.1"; +export const testPlugin: Plugin = + { + name: "TestPlugin", + routes:[ + { + component: TestComponent as ComponentType, + path: "/session", + } + ] +}; + + diff --git a/tests/redis_session_test.ts b/tests/redis_session_test.ts new file mode 100644 index 0000000..033299a --- /dev/null +++ b/tests/redis_session_test.ts @@ -0,0 +1,57 @@ +import { createHandler, ServeHandlerInfo } from "https://deno.land/x/fresh@1.5.4/server.ts"; +import manifest from "./work/fresh.gen.ts"; +import config from "./config/redis_session_test_plugin_fresh.config.ts"; +import { assert, assertEquals } from "$std/testing/asserts.ts"; + +const CONN_INFO: ServeHandlerInfo = { + remoteAddr: { hostname: "127.0.0.1", port: 53496, transport: "tcp" }, +}; + +Deno.test("Redis Session Test", async (t) => { + const handler = await createHandler(manifest, config); + + await t.step("Work Session", async () => { + let resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + assertEquals(resp.status, 200); + + let text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + + const sessionKey = (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; + + resp = await handler(new Request("http://127.0.0.1/session", {headers: {cookie: `session=${sessionKey}`}}), CONN_INFO); + assertEquals(resp.status, 200); + text = await resp.text(); + assertEquals(text.includes("

    count:1

    "), true); + + }); + await t.step("Not Work Session(unset cookie)", async () => { + let resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + assertEquals(resp.status, 200); + + let text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + + resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + assertEquals(resp.status, 200); + text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + + }); + + await t.step("Not Work Session(incorrect cookie)", async () => { + let resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + assertEquals(resp.status, 200); + + let text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + + const sessionKey = (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; + + resp = await handler(new Request("http://127.0.0.1/session", {headers: {cookie: `session=${sessionKey}AA`}}), CONN_INFO); + assertEquals(resp.status, 200); + text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + + }); +}); diff --git a/tests/routes/session_test_plugin.tsx_ b/tests/routes/session_test_plugin.tsx_ new file mode 100644 index 0000000..0858419 --- /dev/null +++ b/tests/routes/session_test_plugin.tsx_ @@ -0,0 +1,66 @@ +import { useSignal } from "@preact/signals"; +import { HandlerContext, Handlers } from "$fresh/server.ts"; +import type { WithSession } from "../../mod.ts"; + +export const handler: Handlers< + unknown, + WithSession<"count" | "a" | "b", "error"> +> = { + GET( + _req: Request, + ctx: HandlerContext>, + ) { + console.log(ctx.state.session.getRawData()); + ctx.state.session.set("b", Number(ctx.state.session.get("b")) + 1); + ctx.state.session.set("a", Number(ctx.state.session.get("a")) + 1); + console.log(ctx.state.session.getRawData()); + + if (Number(ctx.state.session.get("b") == 3)) { + //ctx.state.session.destroy(); + ctx.state.session.rotateKey(); + ctx.state.session.delete("b"); + } + if (Number(ctx.state.session.get("a") == 7)) { + ctx.state.session.destroy(); + } + + return ctx.render(); + }, +}; + +export default function Home( + p: HandlerContext>, +) { + console.log(p.state.session.getRawData()); + //p.state.session.set("a", 1); + const countR = p.state.session.get("count"); + p.state.session.set("count", Number(countR) + 1); + p.state.session.flash("error", `error:${countR}`); + + 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. +

    + +
    +

    const:{countR}

    +

    err:{p.state.session.flash("error")}

    +

    a:{p.state.session.get("a")}

    +

    b:{p.state.session.get("b")}

    + + /a +
    + ); +} diff --git a/tests/routes/session_test_route.tsx b/tests/routes/session_test_route.tsx new file mode 100644 index 0000000..d6f8238 --- /dev/null +++ b/tests/routes/session_test_route.tsx @@ -0,0 +1,16 @@ +import { PageProps } from "$fresh/server.ts"; +import type { WithSession } from "../../mod.ts"; + +export default function Home( + props: PageProps> +) { + const count = props.state.session.get("count") || 0; + props.state.session.set("count", Number(count) + 1); + + return ( +
    +

    count:{count}

    +
    + ); +} + diff --git a/tests/session_test.ts b/tests/session_test.ts new file mode 100644 index 0000000..c065f83 --- /dev/null +++ b/tests/session_test.ts @@ -0,0 +1,133 @@ +import { createSession } from "../src/session.ts"; +import { assertEquals } from "https://deno.land/std@0.208.0/testing/asserts.ts"; + +// テストコードを用意する +Deno.test("Session", async (t) => { + type SessionValueKeys = "KEY_A" | "KEY_B" | "KEY_C"; + type FlashValueKeys = "error" | "success"; + + await t.step("get", () => { + const { session } = createSession( + JSON.parse('{"session": {"KEY_A": 1, "KEY_B": 2, "KEY_C":"3"}}'), + ); + + assertEquals(session.get("KEY_A"), 1); + assertEquals(session.get("KEY_B"), 2); + assertEquals(session.get("KEY_C"), "3"); + }); + + await t.step("delete", () => { + const { session } = createSession( + JSON.parse('{"session": {"KEY_A": 1, "KEY_B": 2, "KEY_C":"3"}}'), + ); + assertEquals(session.get("KEY_A"), 1); + session.delete("KEY_A"); + assertEquals(session.get("KEY_A"), undefined); + }); + + await t.step("list", () => { + const { session } = createSession( + JSON.parse('{"session": {"KEY_A": 1, "KEY_B": 2, "KEY_C":"3"}}'), + ); + assertEquals(session.list(), { KEY_A: 1, KEY_B: 2, KEY_C: "3" }); + }); + + await t.step("has", () => { + const { session } = createSession( + JSON.parse('{"session": {"KEY_A": 1, "KEY_B": 2, "KEY_C":"3"}}'), + ); + assertEquals(session.has("KEY_A"), true); + session.delete("KEY_A"); + assertEquals(session.has("KEY_A"), false); + }); + + await t.step("destroy", () => { + const { session, getDuplicateDataFunction } = createSession< + SessionValueKeys, + FlashValueKeys + >(JSON.parse('{"session": {}}')); + + assertEquals(getDuplicateDataFunction().operations.doDestroy, false); + session.destroy(); + assertEquals(getDuplicateDataFunction().operations.doDestroy, true); + }); + + await t.step("rotateKey", () => { + const { session, getDuplicateDataFunction } = createSession< + SessionValueKeys, + FlashValueKeys + >(JSON.parse('{"session": {}}')); + + assertEquals(getDuplicateDataFunction().operations.doRotateKey, false); + session.rotateKey(); + assertEquals(getDuplicateDataFunction().operations.doRotateKey, true); + }); + + await t.step("flash", () => { + const { session, getDuplicateDataFunction } = createSession< + SessionValueKeys, + FlashValueKeys + >(JSON.parse('{"session": {}}')); + + assertEquals(session.flash("error"), undefined); + session.flash("error", "ERROR MESSAGE"); + assertEquals(session.flash("error"), undefined); + assertEquals(getDuplicateDataFunction().flash.error, "ERROR MESSAGE"); + }); + + await t.step("flash", () => { + const { session, getDuplicateDataFunction } = createSession< + SessionValueKeys, + FlashValueKeys + >(JSON.parse('{"session": {}}')); + + assertEquals(session.flash("error"), undefined); + session.flash("error", "ERROR MESSAGE"); + assertEquals(session.flashNow("error"), "ERROR MESSAGE"); + assertEquals(getDuplicateDataFunction().flash.error, undefined); + }); + + await t.step("clear", () => { + const { session, getDuplicateDataFunction } = createSession< + SessionValueKeys, + FlashValueKeys + >(JSON.parse('{"session": {"KEY_A": 1, "KEY_B": 2, "KEY_C":"3"}}')); + + assertEquals(getDuplicateDataFunction(), { + session: { KEY_A: 1, KEY_B: 2, KEY_C: "3" }, + flash: {}, + operations: { doDestroy: false, doRotateKey: false }, + }); + + session.clear(); + + // session.set の内容が、getDuplicateDataFunction() に反映されていることを確認する + assertEquals(getDuplicateDataFunction(), { + session: {}, + flash: {}, + operations: { doDestroy: false, doRotateKey: false }, + }); + }); + + await t.step("getDuplicateDataFunction", async () => { + const { session, getDuplicateDataFunction } = createSession< + SessionValueKeys, + FlashValueKeys + >(JSON.parse('{"session": {"KEY_A": 1, "KEY_B": 2, "KEY_C":"3"}}')); + + assertEquals(getDuplicateDataFunction(), { + session: { KEY_A: 1, KEY_B: 2, KEY_C: "3" }, + flash: {}, + operations: { doDestroy: false, doRotateKey: false }, + }); + + session.set("KEY_A", 30); + + // session.set の内容が、getDuplicateDataFunction() に反映されていることを確認する + assertEquals(getDuplicateDataFunction(), { + session: { KEY_A: 30, KEY_B: 2, KEY_C: "3" }, + flash: {}, + operations: { doDestroy: false, doRotateKey: false }, + }); + }); +}); diff --git a/tests/wrapper.js b/tests/wrapper.js deleted file mode 100644 index b08e325..0000000 --- a/tests/wrapper.js +++ /dev/null @@ -1,31 +0,0 @@ -import { delay } from "$std/async/delay.ts"; -import { startFreshServer } from "$fresh/tests/test_utils.ts"; - -Deno.env.set("APP_KEY", "something_for_testing"); - -export const BASE_URL = "http://localhost:8000"; - -const myTestWrapper = (args) => (theTests) => async (t) => { - const { serverProcess, lines } = await startFreshServer({ - args, - }); - await theTests(t); - // Stop the Server - await lines.cancel(); - serverProcess.kill("SIGTERM"); - // await for the server to close - await delay(100); -}; - -export const fixtureTestWrapper = myTestWrapper([ - "run", - "-A", - "./tests/fixture/main.ts", -]); - -export const exampleKVStoreTestWrapper = myTestWrapper([ - "run", - "-A", - "--unstable", - "./example/use_kv_store/main.ts", -]); From f9068b3a19e3c8e575a84dcc11a0d19fb1eabb03 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:08:20 +0900 Subject: [PATCH 02/30] formatting --- src/session.ts | 2 +- src/stores/deno_kv_store.ts | 5 +- src/type.ts | 2 +- .../redis_session_test_plugin_fresh.config.ts | 6 +-- tests/cookie_session_test.ts | 53 +++++++++++-------- tests/plugin/test_plugin.ts | 22 ++++---- tests/redis_session_test.ts | 43 +++++++++++---- tests/routes/session_test_route.tsx | 3 +- 8 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src/session.ts b/src/session.ts index b4e66d8..da47068 100644 --- a/src/session.ts +++ b/src/session.ts @@ -61,7 +61,7 @@ export function createSession( duplicateData = this.getRawData(); }, flashNow(key: F) { - const value = { ...flashData, ...newFlashData }[key]! + const value = { ...flashData, ...newFlashData }[key]!; delete newFlashData[key]; duplicateData = this.getRawData(); return value; diff --git a/src/stores/deno_kv_store.ts b/src/stores/deno_kv_store.ts index 297a327..78a94ee 100644 --- a/src/stores/deno_kv_store.ts +++ b/src/stores/deno_kv_store.ts @@ -103,7 +103,10 @@ export async function getDenoKvSession( ): Promise<{ session: Session; sessionCookieSetter: { - (res: Response, cookieOptions: RequiredCookieOptions): Response | Promise; + ( + res: Response, + cookieOptions: RequiredCookieOptions, + ): Response | Promise; }; }> { console.log({ diff --git a/src/type.ts b/src/type.ts index 9f75d0f..88767af 100644 --- a/src/type.ts +++ b/src/type.ts @@ -56,7 +56,7 @@ export interface FreshSessionBaseOptions { excludePath?: string[]; } -export type CookieFreshSessionOptions = FreshSessionBaseOptions +export type CookieFreshSessionOptions = FreshSessionBaseOptions; export interface RequiredCookieFreshSessionOptions extends Required { diff --git a/tests/config/redis_session_test_plugin_fresh.config.ts b/tests/config/redis_session_test_plugin_fresh.config.ts index 928427e..b7374fd 100644 --- a/tests/config/redis_session_test_plugin_fresh.config.ts +++ b/tests/config/redis_session_test_plugin_fresh.config.ts @@ -1,9 +1,9 @@ import { defineConfig } from "$fresh/server.ts"; import { getRedisSessionPlugin } from "../../mod.ts"; import { testPlugin } from "../plugin/test_plugin.ts"; -import Redis from 'https://unpkg.com/ioredis-mock'; -const redis = new Redis() +import Redis from "https://unpkg.com/ioredis-mock"; +const redis = new Redis(); export default defineConfig({ - plugins: [getRedisSessionPlugin("/", {client: redis}), testPlugin], + plugins: [getRedisSessionPlugin("/", { client: redis }), testPlugin], }); diff --git a/tests/cookie_session_test.ts b/tests/cookie_session_test.ts index 0587e05..c3dfc73 100644 --- a/tests/cookie_session_test.ts +++ b/tests/cookie_session_test.ts @@ -1,4 +1,7 @@ -import { createHandler, ServeHandlerInfo } from "https://deno.land/x/fresh@1.5.4/server.ts"; +import { + createHandler, + ServeHandlerInfo, +} from "https://deno.land/x/fresh@1.5.4/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/cookie_session_test_plugin_fresh.config.ts"; import { assert, assertEquals } from "$std/testing/asserts.ts"; @@ -11,35 +14,43 @@ Deno.test("Cookie Session Test", async (t) => { const handler = await createHandler(manifest, config); await t.step("#1 GET /", async () => { - let resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + let resp = await handler( + new Request("http://127.0.0.1/session"), + CONN_INFO, + ); assertEquals(resp.status, 200); let text = await resp.text(); assertEquals(text.includes("

    count:0

    "), true); - const sessionKey = (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; + const sessionKey = + (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; - resp = await handler(new Request("http://127.0.0.1/session", {headers: {cookie: `session=${sessionKey}`}}), CONN_INFO); + resp = await handler( + new Request("http://127.0.0.1/session", { + headers: { cookie: `session=${sessionKey}` }, + }), + CONN_INFO, + ); assertEquals(resp.status, 200); text = await resp.text(); assertEquals(text.includes("

    count:1

    "), true); - }); -// await t.step("#2 POST /", async () => { -// const formData = new FormData(); -// formData.append("text", "Deno!"); -// const req = new Request("http://127.0.0.1/", { -// method: "POST", -// body: formData, -// }); -// const resp = await handler(req, CONN_INFO); -// assertEquals(resp.status, 303); -// }); -// -// await t.step("#3 GET /foo", async () => { -// const resp = await handler(new Request("http://127.0.0.1/foo"), CONN_INFO); -// const text = await resp.text(); -// assert(text.includes("
    Hello Foo!
    ")); -// }); + // await t.step("#2 POST /", async () => { + // const formData = new FormData(); + // formData.append("text", "Deno!"); + // const req = new Request("http://127.0.0.1/", { + // method: "POST", + // body: formData, + // }); + // const resp = await handler(req, CONN_INFO); + // assertEquals(resp.status, 303); + // }); + // + // await t.step("#3 GET /foo", async () => { + // const resp = await handler(new Request("http://127.0.0.1/foo"), CONN_INFO); + // const text = await resp.text(); + // assert(text.includes("
    Hello Foo!
    ")); + // }); }); diff --git a/tests/plugin/test_plugin.ts b/tests/plugin/test_plugin.ts index b23c124..ffec638 100644 --- a/tests/plugin/test_plugin.ts +++ b/tests/plugin/test_plugin.ts @@ -1,16 +1,12 @@ - -import { Plugin, PageProps } from "https://deno.land/x/fresh@1.5.4/server.ts"; +import { PageProps, Plugin } from "https://deno.land/x/fresh@1.5.4/server.ts"; import TestComponent from "../routes/session_test_route.tsx"; import { ComponentType } from "https://esm.sh/preact@10.18.1"; -export const testPlugin: Plugin = - { - name: "TestPlugin", - routes:[ - { - component: TestComponent as ComponentType, - path: "/session", - } - ] +export const testPlugin: Plugin = { + name: "TestPlugin", + routes: [ + { + component: TestComponent as ComponentType, + path: "/session", + }, + ], }; - - diff --git a/tests/redis_session_test.ts b/tests/redis_session_test.ts index 033299a..a085e44 100644 --- a/tests/redis_session_test.ts +++ b/tests/redis_session_test.ts @@ -1,4 +1,7 @@ -import { createHandler, ServeHandlerInfo } from "https://deno.land/x/fresh@1.5.4/server.ts"; +import { + createHandler, + ServeHandlerInfo, +} from "https://deno.land/x/fresh@1.5.4/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/redis_session_test_plugin_fresh.config.ts"; import { assert, assertEquals } from "$std/testing/asserts.ts"; @@ -11,22 +14,33 @@ Deno.test("Redis Session Test", async (t) => { const handler = await createHandler(manifest, config); await t.step("Work Session", async () => { - let resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + let resp = await handler( + new Request("http://127.0.0.1/session"), + CONN_INFO, + ); assertEquals(resp.status, 200); let text = await resp.text(); assertEquals(text.includes("

    count:0

    "), true); - const sessionKey = (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; + const sessionKey = + (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; - resp = await handler(new Request("http://127.0.0.1/session", {headers: {cookie: `session=${sessionKey}`}}), CONN_INFO); + resp = await handler( + new Request("http://127.0.0.1/session", { + headers: { cookie: `session=${sessionKey}` }, + }), + CONN_INFO, + ); assertEquals(resp.status, 200); text = await resp.text(); assertEquals(text.includes("

    count:1

    "), true); - }); await t.step("Not Work Session(unset cookie)", async () => { - let resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + let resp = await handler( + new Request("http://127.0.0.1/session"), + CONN_INFO, + ); assertEquals(resp.status, 200); let text = await resp.text(); @@ -36,22 +50,29 @@ Deno.test("Redis Session Test", async (t) => { assertEquals(resp.status, 200); text = await resp.text(); assertEquals(text.includes("

    count:0

    "), true); - }); await t.step("Not Work Session(incorrect cookie)", async () => { - let resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + let resp = await handler( + new Request("http://127.0.0.1/session"), + CONN_INFO, + ); assertEquals(resp.status, 200); let text = await resp.text(); assertEquals(text.includes("

    count:0

    "), true); - const sessionKey = (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; + const sessionKey = + (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; - resp = await handler(new Request("http://127.0.0.1/session", {headers: {cookie: `session=${sessionKey}AA`}}), CONN_INFO); + resp = await handler( + new Request("http://127.0.0.1/session", { + headers: { cookie: `session=${sessionKey}AA` }, + }), + CONN_INFO, + ); assertEquals(resp.status, 200); text = await resp.text(); assertEquals(text.includes("

    count:0

    "), true); - }); }); diff --git a/tests/routes/session_test_route.tsx b/tests/routes/session_test_route.tsx index d6f8238..1051827 100644 --- a/tests/routes/session_test_route.tsx +++ b/tests/routes/session_test_route.tsx @@ -2,7 +2,7 @@ import { PageProps } from "$fresh/server.ts"; import type { WithSession } from "../../mod.ts"; export default function Home( - props: PageProps> + props: PageProps>, ) { const count = props.state.session.get("count") || 0; props.state.session.set("count", Number(count) + 1); @@ -13,4 +13,3 @@ export default function Home( ); } - From 8fe50ea2a9c231eeeeb3a91024c5ffbef553045a Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:18:25 +0900 Subject: [PATCH 03/30] update action --- .github/workflows/deno.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index b736a26..f9b6783 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -5,9 +5,9 @@ name: Deno Deploy & Test on: push: - branches: ["main","test"] + branches: ["main", "test"] pull_request: - branches: ["main","test"] + branches: ["main", "test"] permissions: id-token: write # This is required to allow the GitHub Action to authenticate with Deno Deploy. @@ -27,17 +27,18 @@ jobs: - name: Setup Deno uses: denoland/setup-deno@v1 - with: - deno-version: v1.35.2 - name: Verify formatting run: deno fmt --check + + - name: Install Fresh + run: deno run -A https://fresh.deno.dev ./tests/work --force --twind --vscode - - name: Cache Deno dependencies - uses: actions/cache@v3 - with: - key: denoDeps-${{ hashFiles('deno.lock') }} - path: ${{ env.DENO_DIR }} +# - name: Cache Deno dependencies +# uses: actions/cache@v3 +# with: +# key: denoDeps-${{ hashFiles('deno.lock') }} +# path: ${{ env.DENO_DIR }} - name: Run tests - run: deno test -A --quiet + run: deno test --unstable -A From d5531115f0cc2c435f018c7ba47891d18cc7c8d4 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:24:58 +0900 Subject: [PATCH 04/30] update deps --- deps.ts | 1 + tests/cookie_session_test.ts | 2 +- tests/redis_session_test.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deps.ts b/deps.ts index 22becac..a0b8dbd 100644 --- a/deps.ts +++ b/deps.ts @@ -13,3 +13,4 @@ export type { MiddlewareHandler, MiddlewareHandlerContext, } from "https://deno.land/x/fresh@1.5.4/server.ts"; +export {assertEquals} from "https://deno.land/std@0.208.0/testing/asserts.ts"; \ No newline at end of file diff --git a/tests/cookie_session_test.ts b/tests/cookie_session_test.ts index c3dfc73..ef2f9b9 100644 --- a/tests/cookie_session_test.ts +++ b/tests/cookie_session_test.ts @@ -4,7 +4,7 @@ import { } from "https://deno.land/x/fresh@1.5.4/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/cookie_session_test_plugin_fresh.config.ts"; -import { assert, assertEquals } from "$std/testing/asserts.ts"; +import {assertEquals} from "../deps.ts"; const CONN_INFO: ServeHandlerInfo = { remoteAddr: { hostname: "127.0.0.1", port: 53496, transport: "tcp" }, diff --git a/tests/redis_session_test.ts b/tests/redis_session_test.ts index a085e44..786853a 100644 --- a/tests/redis_session_test.ts +++ b/tests/redis_session_test.ts @@ -4,7 +4,7 @@ import { } from "https://deno.land/x/fresh@1.5.4/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/redis_session_test_plugin_fresh.config.ts"; -import { assert, assertEquals } from "$std/testing/asserts.ts"; +import {assertEquals} from "../deps.ts"; const CONN_INFO: ServeHandlerInfo = { remoteAddr: { hostname: "127.0.0.1", port: 53496, transport: "tcp" }, From 6054522cbbd23424245ef1ae6673a625a918f102 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:26:26 +0900 Subject: [PATCH 05/30] formatting --- deps.ts | 2 +- tests/cookie_session_test.ts | 2 +- tests/redis_session_test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.ts b/deps.ts index a0b8dbd..3cf7d22 100644 --- a/deps.ts +++ b/deps.ts @@ -13,4 +13,4 @@ export type { MiddlewareHandler, MiddlewareHandlerContext, } from "https://deno.land/x/fresh@1.5.4/server.ts"; -export {assertEquals} from "https://deno.land/std@0.208.0/testing/asserts.ts"; \ No newline at end of file +export { assertEquals } from "https://deno.land/std@0.208.0/testing/asserts.ts"; diff --git a/tests/cookie_session_test.ts b/tests/cookie_session_test.ts index ef2f9b9..6ee4186 100644 --- a/tests/cookie_session_test.ts +++ b/tests/cookie_session_test.ts @@ -4,7 +4,7 @@ import { } from "https://deno.land/x/fresh@1.5.4/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/cookie_session_test_plugin_fresh.config.ts"; -import {assertEquals} from "../deps.ts"; +import { assertEquals } from "../deps.ts"; const CONN_INFO: ServeHandlerInfo = { remoteAddr: { hostname: "127.0.0.1", port: 53496, transport: "tcp" }, diff --git a/tests/redis_session_test.ts b/tests/redis_session_test.ts index 786853a..1513514 100644 --- a/tests/redis_session_test.ts +++ b/tests/redis_session_test.ts @@ -4,7 +4,7 @@ import { } from "https://deno.land/x/fresh@1.5.4/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/redis_session_test_plugin_fresh.config.ts"; -import {assertEquals} from "../deps.ts"; +import { assertEquals } from "../deps.ts"; const CONN_INFO: ServeHandlerInfo = { remoteAddr: { hostname: "127.0.0.1", port: 53496, transport: "tcp" }, From c2d4f63e96f9cbd7095af0f628206f24a4c6866e Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:31:35 +0900 Subject: [PATCH 06/30] update --- .github/workflows/deno.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index f9b6783..01c442a 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -34,6 +34,8 @@ jobs: - name: Install Fresh run: deno run -A https://fresh.deno.dev ./tests/work --force --twind --vscode + - neme: ls + run: ls -la # - name: Cache Deno dependencies # uses: actions/cache@v3 # with: @@ -41,4 +43,4 @@ jobs: # path: ${{ env.DENO_DIR }} - name: Run tests - run: deno test --unstable -A + run: deno test --unstable -A From 9db1e049b8577587fc4aa29fbb0c27bd6bf6975b Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:35:15 +0900 Subject: [PATCH 07/30] update --- .github/workflows/deno.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index 01c442a..fee2940 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -34,7 +34,7 @@ jobs: - name: Install Fresh run: deno run -A https://fresh.deno.dev ./tests/work --force --twind --vscode - - neme: ls + - name: ls run: ls -la # - name: Cache Deno dependencies # uses: actions/cache@v3 From e3a0c8e06457b12e55123dd0eb455c512edb085a Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:40:05 +0900 Subject: [PATCH 08/30] update --- .github/workflows/deno.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index fee2940..3b8e360 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -16,11 +16,11 @@ permissions: jobs: test: runs-on: ubuntu-latest - env: - DENO_ENV: testing - BASE_URL: http://localhost:8000 - DENO_DIR: deno_dir - APP_KEY: not-secret-at-all +# env: +# DENO_ENV: testing +# BASE_URL: http://localhost:8000 +# DENO_DIR: deno_dir +# APP_KEY: not-secret-at-all steps: - name: Setup repo uses: actions/checkout@v3 From e9529140eccbd19290783a8e70f31e28d31d9cef Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:45:49 +0900 Subject: [PATCH 09/30] update --- .github/workflows/deno.yml | 31 +++++++++++++++++-------------- deno.json | 29 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 deno.json diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index 3b8e360..6c45d92 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -16,31 +16,34 @@ permissions: jobs: test: runs-on: ubuntu-latest -# env: -# DENO_ENV: testing -# BASE_URL: http://localhost:8000 -# DENO_DIR: deno_dir -# APP_KEY: not-secret-at-all + # env: + # DENO_ENV: testing + # BASE_URL: http://localhost:8000 + # DENO_DIR: deno_dir + # APP_KEY: not-secret-at-all steps: - name: Setup repo uses: actions/checkout@v3 - name: Setup Deno uses: denoland/setup-deno@v1 - - - name: Verify formatting + + - name: Check version + run: deno -V + + - name: Verify formatting run: deno fmt --check - name: Install Fresh - run: deno run -A https://fresh.deno.dev ./tests/work --force --twind --vscode - + run: deno run -A https://fresh.deno.dev ./tests/work --force --twind --vscode + - name: ls run: ls -la -# - name: Cache Deno dependencies -# uses: actions/cache@v3 -# with: -# key: denoDeps-${{ hashFiles('deno.lock') }} -# path: ${{ env.DENO_DIR }} + # - name: Cache Deno dependencies + # uses: actions/cache@v3 + # with: + # key: denoDeps-${{ hashFiles('deno.lock') }} + # path: ${{ env.DENO_DIR }} - name: Run tests run: deno test --unstable -A diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..16f51fa --- /dev/null +++ b/deno.json @@ -0,0 +1,29 @@ +{ + "lock": false, + "lint": { + "rules": { + "tags": [ + "fresh", + "recommended" + ] + } + }, + "exclude": [ + "**/_fresh/*" + ], + "imports": { + "$fresh/": "https://deno.land/x/fresh/", + "preact": "https://esm.sh/preact@10.18.1", + "preact/": "https://esm.sh/preact@10.18.1/", + "preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.2.2", + "@preact/signals": "https://esm.sh/*@preact/signals@1.2.1", + "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.0", + "twind": "https://esm.sh/twind@0.16.19", + "twind/": "https://esm.sh/twind@0.16.19/", + "$std/": "https://deno.land/std/" + }, + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "preact" + } +} From 905dd91eaf15d48a28321fbdf30caafd6871fa3b Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:54:08 +0900 Subject: [PATCH 10/30] update --- .github/workflows/deno.yml | 8 +++++++- deno.json | 29 ----------------------------- 2 files changed, 7 insertions(+), 30 deletions(-) delete mode 100644 deno.json diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index 6c45d92..d4d1ce4 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -37,7 +37,13 @@ jobs: - name: Install Fresh run: deno run -A https://fresh.deno.dev ./tests/work --force --twind --vscode - - name: ls + - name: ls 1 + run: ls -la + + - name: Move deno.json + run: mv ./test/work/deno.json ./deno.json + + - name: ls 2 run: ls -la # - name: Cache Deno dependencies # uses: actions/cache@v3 diff --git a/deno.json b/deno.json deleted file mode 100644 index 16f51fa..0000000 --- a/deno.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "lock": false, - "lint": { - "rules": { - "tags": [ - "fresh", - "recommended" - ] - } - }, - "exclude": [ - "**/_fresh/*" - ], - "imports": { - "$fresh/": "https://deno.land/x/fresh/", - "preact": "https://esm.sh/preact@10.18.1", - "preact/": "https://esm.sh/preact@10.18.1/", - "preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.2.2", - "@preact/signals": "https://esm.sh/*@preact/signals@1.2.1", - "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.0", - "twind": "https://esm.sh/twind@0.16.19", - "twind/": "https://esm.sh/twind@0.16.19/", - "$std/": "https://deno.land/std/" - }, - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "preact" - } -} From f8f2b217d78c4e87c9d6e6fb5f34d0ea5d88f607 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:56:14 +0900 Subject: [PATCH 11/30] update --- .github/workflows/deno.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index d4d1ce4..7203854 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -41,7 +41,7 @@ jobs: run: ls -la - name: Move deno.json - run: mv ./test/work/deno.json ./deno.json + run: mv ./tests/work/deno.json ./deno.json - name: ls 2 run: ls -la From 38ef3c4824677475dccf07b98527bf4e25f37fcf Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 01:58:10 +0900 Subject: [PATCH 12/30] update --- .github/workflows/deno.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index 7203854..13103f0 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -16,11 +16,6 @@ permissions: jobs: test: runs-on: ubuntu-latest - # env: - # DENO_ENV: testing - # BASE_URL: http://localhost:8000 - # DENO_DIR: deno_dir - # APP_KEY: not-secret-at-all steps: - name: Setup repo uses: actions/checkout@v3 @@ -36,20 +31,9 @@ jobs: - name: Install Fresh run: deno run -A https://fresh.deno.dev ./tests/work --force --twind --vscode - - - name: ls 1 - run: ls -la - name: Move deno.json run: mv ./tests/work/deno.json ./deno.json - - name: ls 2 - run: ls -la - # - name: Cache Deno dependencies - # uses: actions/cache@v3 - # with: - # key: denoDeps-${{ hashFiles('deno.lock') }} - # path: ${{ env.DENO_DIR }} - - name: Run tests run: deno test --unstable -A From a17af71dea05a71df7f69018ad1023af82b3d3a9 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Fri, 1 Dec 2023 02:44:43 +0900 Subject: [PATCH 13/30] update --- README.md | 230 +++++++++++++++++++++++++++++------------------------- mod.ts | 1 + 2 files changed, 124 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 8140f73..2baa744 100644 --- a/README.md +++ b/README.md @@ -4,54 +4,94 @@ Dead simple cookie-based session for [Deno Fresh](https://fresh.deno.dev). ## Get started -Fresh Session comes with a simple middleware to add at the root of your project, -which will create or resolve a session from the request cookie. +Fresh Session provides plug-ins that add Session functionality. -### Install / Import +## Install / Import You can import Fresh Session like so: ```ts import { - cookieSession, - CookieSessionStorage, - createCookieSessionStorage, - Session, - WithSession, -} from "https://deno.land/x/fresh_session@0.2.0/mod.ts"; + getCookieSessionPlugin, + getRedisSessionPlugin, + getDenoKvSessionPlugin + type CookieFreshSessionOptions, + type DenoKvFreshSessionOptions, + type RedisFreshSessionOptions, + type Session, + type WithSession, +} from "https://deno.land/x/fresh_session@beta-0.3.0/mod.ts"; ``` -### Setup secret key +## Usage + +### JWT-based Cookie Session + +```ts +// fresh.config.ts +import { defineConfig } from "$fresh/server.ts"; +import twindPlugin from "$fresh/plugins/twind.ts"; +import twindConfig from "./twind.config.ts"; + +import { getCookieSessionPlugin} from "../fresh-session-next/mod.ts"; + +export default defineConfig({ + plugins: [ + twindPlugin(twindConfig), + getCookieSessionPlugin("/"), + ], +}); +``` + +**⚠ Setup secret key** Fresh Session currently uses [JSON Web Token](https://jwt.io/) under the hood to create and manage session in the cookies. JWT requires a secret key to sign new tokens. Fresh Session uses the secret key from your [environment variable](https://deno.land/std/dotenv/load.ts) -`APP_KEY`. - -If you don't know how to setup environment variable locally, I wrote -[an article about .env file in Deno Fresh](https://xstevenyung.com/blog/read-.env-file-in-deno-fresh). +`APP_SESSION_CRYPTO_KEY`. -### Create a root middleware (`./routes/_middleware.ts`) +### Sessions using Redis as the backend ```ts -import { MiddlewareHandlerContext } from "$fresh/server.ts"; -import { cookieSession, WithSession } from "fresh-session"; - -export type State = {} & WithSession; +// fresh.config.ts +import { defineConfig } from "$fresh/server.ts"; +import twindPlugin from "$fresh/plugins/twind.ts"; +import twindConfig from "./twind.config.ts"; + +import { getRedisSessionPlugin } from "../fresh-session-next/mod.ts"; + +// any redis client. ex. ioredis-mock, redis, upstash-redis +import Redis from 'https://unpkg.com/ioredis-mock'; +const redis = new Redis() + +export default defineConfig({ + plugins: [ + twindPlugin(twindConfig), + getRedisSessionPlugin("/", {client: redis}), + ], +}); +``` -const session = cookieSession(); +### Sessions using Deno.KV as the backend -function sessionHandler(req: Request, ctx: MiddlewareHandlerContext) { - return session(req, ctx); -} -export const handler = [sessionHandler]; +```ts +// fresh.config.ts +import { defineConfig } from "$fresh/server.ts"; +import twindPlugin from "$fresh/plugins/twind.ts"; +import twindConfig from "./twind.config.ts"; + +import { getDenoKvSessionPlugin} from "../fresh-session-next/mod.ts"; + +export default defineConfig({ + plugins: [ + twindPlugin(twindConfig), + getDenoKvSessionPlugin("/", {client: await Deno.openKv(":memory:")}), + ], +}); ``` -Learn more about -[Fresh route middleware](https://fresh.deno.dev/docs/concepts/middleware). - ### Interact with the session in your routes Now that the middleware is setup, it's going to handle creating/resolving @@ -61,49 +101,50 @@ interacting with your session. ```tsx // ./routes/dashboard.tsx import { Handlers, PageProps } from "$fresh/server.ts"; -import { WithSession } from "https://deno.land/x/fresh_session@0.2.0/mod.ts"; - -export type Data = { session: Record }; +import type { WithSession } from "https://deno.land/x/fresh_session@beta-0.3.0/mod.ts"; export const handler: Handlers< - Data, - WithSession // indicate with Typescript that the session is in the `ctx.state` + unknown, + WithSession<"KEY_A" | "KEY_B" | "KEY_C", "success"> > = { GET(_req, ctx) { // The session is accessible via the `ctx.state` const { session } = ctx.state; - // Access data stored in the session - session.get("email"); - // Set new value in the session - session.set("email", "hello@deno.dev"); - // returns `true` if the session has a value with a specific key, else `false` - session.has("email"); - // clear all the session data + // Session methods + // Set session value set. + session.set("KEY_A", "SESSION-DATA"); + // get session value. + session.get("KEY_A"); + // Verify session key registration status. + session.has("KEY_A"); + // Session value delete. + session.delete("KEY_A") + // Get session values all. + session.list() + // Session values clear. session.clear(); - // Access all session data value as an object - session.data; - // Add flash data which will disappear after accessing it + + + // Session operation methods + // Destroy session key and data. + session.destroy() + // Session key rotate. + session.rotateKey() + + // Flash method + // The data set in flash can be used for the next access. session.flash("success", "Successfully flashed a message!"); - // Accessing the flashed data - // /!\ This flashed data will disappear after accessing it one time. session.flash("success"); - // Session Key Rotation only kv store and redis store. - // Is not work in cookie store. - - // Rotate the session key. Only supported by the kv store and redis store, not the cookie store. - // If using the session for authentication, with a kv or redis store, it is recommended to rotate the key at login to prevent session fixation attack. - // The cookie store is immune from this issue. - session.keyRotate(); + // If you want to use the set value in the access, use 'flashNow'. + session.flashNow("success"); - return ctx.render({ - session: session.data, // You can pass the whole session data to the page - }); + return ctx.render(); }, }; -export default function Dashboard({ data }: PageProps) { - return
    You are logged in as {data.session.email}
    ; +export default function Dashboard(props: PageProps>) { + return
    Session Data [KEY_A]: {props.state.session.get("KEY_A")}
    ; } ``` @@ -112,57 +153,32 @@ export default function Dashboard({ data }: PageProps) { session value is cookie. can set the option for cookie. ```ts -import { cookieSession } from "fresh-session"; - -export const handler = [ - cookieSession({ - maxAge: 30, //Session keep is 30 seconds. - httpOnly: true, - }), -]; -``` - -## cookie session based on Redis - -In addition to JWT, values can be stored in Redis. - -```ts -import { redisSession } from "fresh-session/mod.ts"; -import { connect } from "redis/mod.ts"; - -const redis = await connect({ - hostname: "something redis server", - port: 6379, -}); - -export const handler = [redisSession(redis)]; - -// or Customizable cookie options and Redis key prefix - -export const handler = [ - redisSession(redis, { - keyPrefix: "S_", - maxAge: 10, - }), -]; -``` - -## FAQ & Troubleshooting Errors - -Some common questions and troubleshooting errors. - -### "TypeError: Headers are immutable." - -If you are receiving this error, you are likely using a Response.redirect, which -makes the headers immutable. A workaround for this is to use the following -instead: - -```ts -new Response(null, { - status: 302, - headers: { - Location: "your-url", - }, +import { PartialCookieOptions } from "https://deno.land/x/fresh_session@beta-0.3.0/mod.ts"; + +// type PartialCookieOptions = { +// maxAge?: number | undefined; +// domain?: string | undefined; +// path?: string | undefined; +// secure?: boolean | undefined; +// httpOnly?: boolean | undefined; +// sameSite?: "Strict" | "Lax" | "None" | undefined; +// } + +import { defineConfig } from "$fresh/server.ts"; +import twindPlugin from "$fresh/plugins/twind.ts"; +import twindConfig from "./twind.config.ts"; + +import { getDenoKvSessionPlugin } from "[../fresh-session-next/mod.ts](https://deno.land/x/fresh_session@beta-0.3.0/mod.ts)"; + +export default defineConfig({ + plugins: [ + twindPlugin(twindConfig), + getDenoKvSessionPlugin("/", { + client: await Deno.openKv(":memory:"), + cookieOptions:{maxAge: 60 * 10} + } + ), + ], }); ``` diff --git a/mod.ts b/mod.ts index ef639e7..d6e4232 100644 --- a/mod.ts +++ b/mod.ts @@ -7,4 +7,5 @@ export type { RedisFreshSessionOptions, Session, WithSession, + PartialCookieOptions } from "./src/type.ts"; From 7de6e2864df183481b6089bb975496088326d3bb Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Sat, 2 Dec 2023 05:29:37 +0900 Subject: [PATCH 14/30] formatting --- README.md | 35 +++++++++++++++++++---------------- mod.ts | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 2baa744..f6aa731 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ import { defineConfig } from "$fresh/server.ts"; import twindPlugin from "$fresh/plugins/twind.ts"; import twindConfig from "./twind.config.ts"; -import { getCookieSessionPlugin} from "../fresh-session-next/mod.ts"; +import { getCookieSessionPlugin } from "../fresh-session-next/mod.ts"; export default defineConfig({ plugins: [ @@ -63,13 +63,13 @@ import twindConfig from "./twind.config.ts"; import { getRedisSessionPlugin } from "../fresh-session-next/mod.ts"; // any redis client. ex. ioredis-mock, redis, upstash-redis -import Redis from 'https://unpkg.com/ioredis-mock'; -const redis = new Redis() +import Redis from "https://unpkg.com/ioredis-mock"; +const redis = new Redis(); export default defineConfig({ plugins: [ twindPlugin(twindConfig), - getRedisSessionPlugin("/", {client: redis}), + getRedisSessionPlugin("/", { client: redis }), ], }); ``` @@ -82,12 +82,12 @@ import { defineConfig } from "$fresh/server.ts"; import twindPlugin from "$fresh/plugins/twind.ts"; import twindConfig from "./twind.config.ts"; -import { getDenoKvSessionPlugin} from "../fresh-session-next/mod.ts"; +import { getDenoKvSessionPlugin } from "../fresh-session-next/mod.ts"; export default defineConfig({ plugins: [ twindPlugin(twindConfig), - getDenoKvSessionPlugin("/", {client: await Deno.openKv(":memory:")}), + getDenoKvSessionPlugin("/", { client: await Deno.openKv(":memory:") }), ], }); ``` @@ -119,18 +119,17 @@ export const handler: Handlers< // Verify session key registration status. session.has("KEY_A"); // Session value delete. - session.delete("KEY_A") + session.delete("KEY_A"); // Get session values all. - session.list() + session.list(); // Session values clear. session.clear(); - // Session operation methods // Destroy session key and data. - session.destroy() + session.destroy(); // Session key rotate. - session.rotateKey() + session.rotateKey(); // Flash method // The data set in flash can be used for the next access. @@ -143,7 +142,12 @@ export const handler: Handlers< }, }; -export default function Dashboard(props: PageProps>) { +export default function Dashboard( + props: PageProps< + unknown, + WithSession<"KEY_A" | "KEY_B" | "KEY_C", "success"> + >, +) { return
    Session Data [KEY_A]: {props.state.session.get("KEY_A")}
    ; } ``` @@ -174,10 +178,9 @@ export default defineConfig({ plugins: [ twindPlugin(twindConfig), getDenoKvSessionPlugin("/", { - client: await Deno.openKv(":memory:"), - cookieOptions:{maxAge: 60 * 10} - } - ), + client: await Deno.openKv(":memory:"), + cookieOptions: { maxAge: 60 * 10 }, + }), ], }); ``` diff --git a/mod.ts b/mod.ts index d6e4232..a957212 100644 --- a/mod.ts +++ b/mod.ts @@ -4,8 +4,8 @@ export * from "./src/plugins/deno_kv_plugin.ts"; export type { CookieFreshSessionOptions, DenoKvFreshSessionOptions, + PartialCookieOptions, RedisFreshSessionOptions, Session, WithSession, - PartialCookieOptions } from "./src/type.ts"; From c3fee2a0b4d75af3bce6e54b73d5e9008ea45be9 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Sat, 2 Dec 2023 05:32:36 +0900 Subject: [PATCH 15/30] update action --- .github/workflows/deno.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index 13103f0..01d8205 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -1,13 +1,16 @@ # This workflow will install Deno then run Deno fmt and test. # For more information see: https://github.com/denoland/setup-deno -name: Deno Deploy & Test +name: Test on: push: branches: ["main", "test"] pull_request: branches: ["main", "test"] + schedule: + # Run every Monday at 00:00 UTC + - cron: '0 0 * * 1' permissions: id-token: write # This is required to allow the GitHub Action to authenticate with Deno Deploy. From 91ee815a241ec025fab5349c408818901fc9585f Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Sat, 2 Dec 2023 05:45:22 +0900 Subject: [PATCH 16/30] update action --- .gitignore | 2 ++ tests/plugin/test_plugin.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a5063c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tests/work +deno.json \ No newline at end of file diff --git a/tests/plugin/test_plugin.ts b/tests/plugin/test_plugin.ts index ffec638..bf4d546 100644 --- a/tests/plugin/test_plugin.ts +++ b/tests/plugin/test_plugin.ts @@ -1,6 +1,6 @@ import { PageProps, Plugin } from "https://deno.land/x/fresh@1.5.4/server.ts"; import TestComponent from "../routes/session_test_route.tsx"; -import { ComponentType } from "https://esm.sh/preact@10.18.1"; +import { ComponentType } from "preact"; export const testPlugin: Plugin = { name: "TestPlugin", routes: [ From fd79f5b27fd9bb094a8f2818d20383e80ba82735 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Sat, 2 Dec 2023 05:53:49 +0900 Subject: [PATCH 17/30] update action --- .github/workflows/deno.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index 01d8205..6096288 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -33,7 +33,7 @@ jobs: run: deno fmt --check - name: Install Fresh - run: deno run -A https://fresh.deno.dev ./tests/work --force --twind --vscode + run: deno run -A https://deno.land/x/fresh@1.5.4/init.ts ./tests/work --force --twind --tailwind --vscode - name: Move deno.json run: mv ./tests/work/deno.json ./deno.json From c70104ade5ff44963bfca23f4183ca34691b72b5 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Sat, 2 Dec 2023 09:01:14 +0900 Subject: [PATCH 18/30] update module load --- deps.ts | 2 +- tests/cookie_session_test.ts | 2 +- tests/plugin/test_plugin.ts | 2 +- tests/redis_session_test.ts | 2 +- tests/session_test.ts | 1 - 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/deps.ts b/deps.ts index 3cf7d22..5dd2e5d 100644 --- a/deps.ts +++ b/deps.ts @@ -12,5 +12,5 @@ export { export type { MiddlewareHandler, MiddlewareHandlerContext, -} from "https://deno.land/x/fresh@1.5.4/server.ts"; +} from "https://deno.land/x/fresh@1.6.0/server.ts"; export { assertEquals } from "https://deno.land/std@0.208.0/testing/asserts.ts"; diff --git a/tests/cookie_session_test.ts b/tests/cookie_session_test.ts index 6ee4186..5613843 100644 --- a/tests/cookie_session_test.ts +++ b/tests/cookie_session_test.ts @@ -1,7 +1,7 @@ import { createHandler, ServeHandlerInfo, -} from "https://deno.land/x/fresh@1.5.4/server.ts"; +} from "$fresh/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/cookie_session_test_plugin_fresh.config.ts"; import { assertEquals } from "../deps.ts"; diff --git a/tests/plugin/test_plugin.ts b/tests/plugin/test_plugin.ts index bf4d546..d3d74f8 100644 --- a/tests/plugin/test_plugin.ts +++ b/tests/plugin/test_plugin.ts @@ -1,4 +1,4 @@ -import { PageProps, Plugin } from "https://deno.land/x/fresh@1.5.4/server.ts"; +import { PageProps, Plugin } from "$fresh/server.ts"; import TestComponent from "../routes/session_test_route.tsx"; import { ComponentType } from "preact"; export const testPlugin: Plugin = { diff --git a/tests/redis_session_test.ts b/tests/redis_session_test.ts index 1513514..1da84a3 100644 --- a/tests/redis_session_test.ts +++ b/tests/redis_session_test.ts @@ -1,7 +1,7 @@ import { createHandler, ServeHandlerInfo, -} from "https://deno.land/x/fresh@1.5.4/server.ts"; +} from "$fresh/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/redis_session_test_plugin_fresh.config.ts"; import { assertEquals } from "../deps.ts"; diff --git a/tests/session_test.ts b/tests/session_test.ts index c065f83..f4a560c 100644 --- a/tests/session_test.ts +++ b/tests/session_test.ts @@ -1,7 +1,6 @@ import { createSession } from "../src/session.ts"; import { assertEquals } from "https://deno.land/std@0.208.0/testing/asserts.ts"; -// テストコードを用意する Deno.test("Session", async (t) => { type SessionValueKeys = "KEY_A" | "KEY_B" | "KEY_C"; type FlashValueKeys = "error" | "success"; From 8d75bef6f117741d50a614d386981fd0d9c710fb Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Sat, 2 Dec 2023 09:03:01 +0900 Subject: [PATCH 19/30] formatting --- .github/workflows/deno.yml | 5 ++++- tests/cookie_session_test.ts | 5 +---- tests/redis_session_test.ts | 5 +---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index 6096288..db91401 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -33,10 +33,13 @@ jobs: run: deno fmt --check - name: Install Fresh - run: deno run -A https://deno.land/x/fresh@1.5.4/init.ts ./tests/work --force --twind --tailwind --vscode + run: deno run -A https://deno.land/x/fresh/init.ts ./tests/work --force --twind --tailwind --vscode - name: Move deno.json run: mv ./tests/work/deno.json ./deno.json + - name: view deno.json + run: cat ./deno.json + - name: Run tests run: deno test --unstable -A diff --git a/tests/cookie_session_test.ts b/tests/cookie_session_test.ts index 5613843..4a29245 100644 --- a/tests/cookie_session_test.ts +++ b/tests/cookie_session_test.ts @@ -1,7 +1,4 @@ -import { - createHandler, - ServeHandlerInfo, -} from "$fresh/server.ts"; +import { createHandler, ServeHandlerInfo } from "$fresh/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/cookie_session_test_plugin_fresh.config.ts"; import { assertEquals } from "../deps.ts"; diff --git a/tests/redis_session_test.ts b/tests/redis_session_test.ts index 1da84a3..9b1fce3 100644 --- a/tests/redis_session_test.ts +++ b/tests/redis_session_test.ts @@ -1,7 +1,4 @@ -import { - createHandler, - ServeHandlerInfo, -} from "$fresh/server.ts"; +import { createHandler, ServeHandlerInfo } from "$fresh/server.ts"; import manifest from "./work/fresh.gen.ts"; import config from "./config/redis_session_test_plugin_fresh.config.ts"; import { assertEquals } from "../deps.ts"; From 14bbdfb93b496c2b4c7dafc8fdc913895d9bf4fd Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Tue, 5 Dec 2023 09:08:12 +0900 Subject: [PATCH 20/30] remove console --- src/stores/cookie_store.ts | 2 +- src/stores/deno_kv_store.ts | 29 +---------------------------- src/utils/request.ts | 4 ---- 3 files changed, 2 insertions(+), 33 deletions(-) diff --git a/src/stores/cookie_store.ts b/src/stores/cookie_store.ts index 08175e2..8be1321 100644 --- a/src/stores/cookie_store.ts +++ b/src/stores/cookie_store.ts @@ -38,7 +38,7 @@ async function sessionDataFromJwt( return { session: session || {}, flash: flash || {} }; } catch (e) { console.log(e); - console.warn("Invalid JWT token, creating new session..."); + console.error("Invalid JWT token, creating new session..."); return { session: {}, flash: {} }; } } diff --git a/src/stores/deno_kv_store.ts b/src/stores/deno_kv_store.ts index 78a94ee..446fb99 100644 --- a/src/stores/deno_kv_store.ts +++ b/src/stores/deno_kv_store.ts @@ -19,14 +19,6 @@ async function sessionDataFromDenoKv( ...baseKeyPath, sessionKey, ]); - console.log("sessionKey", sessionKey); - console.log("payload", payload); - console.log( - await client.get([ - ...baseKeyPath, - sessionKey, - ]), - ); if (!payload) { return { session: {}, flash: {} }; @@ -71,19 +63,7 @@ function getSessionCookieSetterFunction( } if (!operations.doDestroy) { - console.log(baseKeyPath); - console.log([...baseKeyPath, newSessionKey], payload, { - expireIn: cookieOptions.maxAge, - }); - - const RRRR = await client.set([...baseKeyPath, newSessionKey], payload, { - //expireIn: cookieOptions.maxAge * 1000, - }); - console.log("RRRR", RRRR); - console.log( - "RRRR", - await client.get([...baseKeyPath, sessionKey]), - ); + await client.set([...baseKeyPath, newSessionKey], payload, {expireIn: 0}); } return setSessionText(res, newSessionKey, newCookieOptions); @@ -109,13 +89,6 @@ export async function getDenoKvSession( ): Response | Promise; }; }> { - console.log({ - req, - cookieName, - keyPrefix, - client, - }); - const sessionKey = getSessionPayloadFromCookie(req, cookieName); if (!sessionKey) { diff --git a/src/utils/request.ts b/src/utils/request.ts index 474cb7e..7b942ac 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,8 +1,4 @@ import { getCookies } from "../../deps.ts"; -//export function getSessionText(req: Request): string | null { -// const { sessionText } = getCookies(req.headers); -// return sessionText; -//} export function getSessionPayloadFromCookie( req: Request, From 5ef29864ca7dbda6ad402b03714a3bc286c436cb Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Tue, 5 Dec 2023 09:47:52 +0900 Subject: [PATCH 21/30] formating --- src/stores/deno_kv_store.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/stores/deno_kv_store.ts b/src/stores/deno_kv_store.ts index 446fb99..daccbf9 100644 --- a/src/stores/deno_kv_store.ts +++ b/src/stores/deno_kv_store.ts @@ -63,7 +63,9 @@ function getSessionCookieSetterFunction( } if (!operations.doDestroy) { - await client.set([...baseKeyPath, newSessionKey], payload, {expireIn: 0}); + await client.set([...baseKeyPath, newSessionKey], payload, { + expireIn: 0, + }); } return setSessionText(res, newSessionKey, newCookieOptions); From 1c409f383bab24e5f7479a6565318af1521140e8 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Tue, 5 Dec 2023 23:02:07 +0900 Subject: [PATCH 22/30] add coverage --- .github/workflows/{deno.yml => test.yml} | 8 +++++++- src/stores/cookie_store.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) rename .github/workflows/{deno.yml => test.yml} (73%) diff --git a/.github/workflows/deno.yml b/.github/workflows/test.yml similarity index 73% rename from .github/workflows/deno.yml rename to .github/workflows/test.yml index db91401..07321f8 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/test.yml @@ -42,4 +42,10 @@ jobs: run: cat ./deno.json - name: Run tests - run: deno test --unstable -A + run: deno test --unstable --allow-read --allow-write --allow-env --allow-net --coverage=./coverage + + - name: view coverage + run: | + deno install -A --no-check -n code-coverage https://deno.land/x/code_coverage/cli.ts && + deno coverage --lcov --output=lcov.info ./coverage/ && + code-coverage --file lcov.info \ No newline at end of file diff --git a/src/stores/cookie_store.ts b/src/stores/cookie_store.ts index 8be1321..19036a7 100644 --- a/src/stores/cookie_store.ts +++ b/src/stores/cookie_store.ts @@ -37,7 +37,7 @@ async function sessionDataFromJwt( const { session, flash } = payload; return { session: session || {}, flash: flash || {} }; } catch (e) { - console.log(e); + console.error(e); console.error("Invalid JWT token, creating new session..."); return { session: {}, flash: {} }; } From cd4aa21aa6464f51abef23293139ae377eee5381 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Tue, 5 Dec 2023 23:06:54 +0900 Subject: [PATCH 23/30] add coverage exclude --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 07321f8..bcf19b4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,5 +47,5 @@ jobs: - name: view coverage run: | deno install -A --no-check -n code-coverage https://deno.land/x/code_coverage/cli.ts && - deno coverage --lcov --output=lcov.info ./coverage/ && + deno coverage --exclude=tests/work/ --lcov --output=lcov.info ./coverage/ && code-coverage --file lcov.info \ No newline at end of file From 8a00556b854190740cdd292b6fa123a5b5ef15f9 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Tue, 5 Dec 2023 23:11:32 +0900 Subject: [PATCH 24/30] update test --- tests/cookie_session_test.ts | 57 +++++++++++++++++++++++++----------- tests/redis_session_test.ts | 1 + 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/tests/cookie_session_test.ts b/tests/cookie_session_test.ts index 4a29245..24ccd12 100644 --- a/tests/cookie_session_test.ts +++ b/tests/cookie_session_test.ts @@ -10,7 +10,7 @@ const CONN_INFO: ServeHandlerInfo = { Deno.test("Cookie Session Test", async (t) => { const handler = await createHandler(manifest, config); - await t.step("#1 GET /", async () => { + await t.step("Work Session", async () => { let resp = await handler( new Request("http://127.0.0.1/session"), CONN_INFO, @@ -34,20 +34,43 @@ Deno.test("Cookie Session Test", async (t) => { assertEquals(text.includes("

    count:1

    "), true); }); - // await t.step("#2 POST /", async () => { - // const formData = new FormData(); - // formData.append("text", "Deno!"); - // const req = new Request("http://127.0.0.1/", { - // method: "POST", - // body: formData, - // }); - // const resp = await handler(req, CONN_INFO); - // assertEquals(resp.status, 303); - // }); - // - // await t.step("#3 GET /foo", async () => { - // const resp = await handler(new Request("http://127.0.0.1/foo"), CONN_INFO); - // const text = await resp.text(); - // assert(text.includes("
    Hello Foo!
    ")); - // }); + await t.step("Not Work Session(unset cookie)", async () => { + let resp = await handler( + new Request("http://127.0.0.1/session"), + CONN_INFO, + ); + assertEquals(resp.status, 200); + + let text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + + resp = await handler(new Request("http://127.0.0.1/session"), CONN_INFO); + assertEquals(resp.status, 200); + text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + }); + + await t.step("Not Work Session(incorrect cookie)", async () => { + let resp = await handler( + new Request("http://127.0.0.1/session"), + CONN_INFO, + ); + assertEquals(resp.status, 200); + + let text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + + const sessionKey = + (resp.headers.get("set-cookie")!).split("session=")[1].split(";")[0]; + + resp = await handler( + new Request("http://127.0.0.1/session", { + headers: { cookie: `session=${sessionKey}AA` }, + }), + CONN_INFO, + ); + assertEquals(resp.status, 200); + text = await resp.text(); + assertEquals(text.includes("

    count:0

    "), true); + }); }); diff --git a/tests/redis_session_test.ts b/tests/redis_session_test.ts index 9b1fce3..f261cbf 100644 --- a/tests/redis_session_test.ts +++ b/tests/redis_session_test.ts @@ -33,6 +33,7 @@ Deno.test("Redis Session Test", async (t) => { text = await resp.text(); assertEquals(text.includes("

    count:1

    "), true); }); + await t.step("Not Work Session(unset cookie)", async () => { let resp = await handler( new Request("http://127.0.0.1/session"), From a4b06441bd3f1b65b37a747a2db039884a9f4a2c Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Tue, 5 Dec 2023 23:17:10 +0900 Subject: [PATCH 25/30] upcate action --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bcf19b4..f00944f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,6 +46,7 @@ jobs: - name: view coverage run: | - deno install -A --no-check -n code-coverage https://deno.land/x/code_coverage/cli.ts && + # reference: https://github.com/jhechtf/code-coverage + deno install --allow-read --no-check -n code-coverage https://deno.land/x/code_coverage/cli.ts && deno coverage --exclude=tests/work/ --lcov --output=lcov.info ./coverage/ && code-coverage --file lcov.info \ No newline at end of file From 0654c01a6e7fd509475e536127de04990c4762b1 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Tue, 5 Dec 2023 23:18:54 +0900 Subject: [PATCH 26/30] update action --- .github/workflows/test.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f00944f..821cbc2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,12 +12,10 @@ on: # Run every Monday at 00:00 UTC - cron: '0 0 * * 1' -permissions: - id-token: write # This is required to allow the GitHub Action to authenticate with Deno Deploy. - contents: read - jobs: test: + permissions: + contents: read runs-on: ubuntu-latest steps: - name: Setup repo From 599b3b5c5a7b935e836be63c75f905beb3521cad Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Tue, 20 Feb 2024 23:58:51 +0900 Subject: [PATCH 27/30] update fresh install options --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 821cbc2..845cfec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: run: deno fmt --check - name: Install Fresh - run: deno run -A https://deno.land/x/fresh/init.ts ./tests/work --force --twind --tailwind --vscode + run: deno run -A https://deno.land/x/fresh/init.ts ./tests/work --force --tailwind --vscode - name: Move deno.json run: mv ./tests/work/deno.json ./deno.json From 1a09812c74ff0902cb5345df92cc85a2c397b09c Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Wed, 21 Feb 2024 00:00:43 +0900 Subject: [PATCH 28/30] update fresh install options --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 845cfec..0d03968 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,4 +47,4 @@ jobs: # reference: https://github.com/jhechtf/code-coverage deno install --allow-read --no-check -n code-coverage https://deno.land/x/code_coverage/cli.ts && deno coverage --exclude=tests/work/ --lcov --output=lcov.info ./coverage/ && - code-coverage --file lcov.info \ No newline at end of file + code-coverage --file lcov.info From 6326b654763e8d7b6bd0854ad6045ac10f75a17f Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Wed, 21 Feb 2024 00:43:20 +0900 Subject: [PATCH 29/30] update actions --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0d03968..e909be5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,7 +5,7 @@ name: Test on: push: - branches: ["main", "test"] + branches: ["main", "test", "feature/*"] pull_request: branches: ["main", "test"] schedule: From 7be732fb32c544a3df6ebe58844259a96f8a6928 Mon Sep 17 00:00:00 2001 From: Octo8080 Date: Wed, 21 Feb 2024 01:40:15 +0900 Subject: [PATCH 30/30] updete --- .github/workflows/test.yml | 2 +- deps.ts | 4 +++- src/plugins/cookie_plugin.ts | 3 ++- tests/config/cookie_session_test_plugin_fresh.config.ts | 5 ++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e909be5..058b731 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,7 +40,7 @@ jobs: run: cat ./deno.json - name: Run tests - run: deno test --unstable --allow-read --allow-write --allow-env --allow-net --coverage=./coverage + run: deno test --unstable-kv --allow-read --allow-write --allow-env --allow-net --coverage=./coverage - name: view coverage run: | diff --git a/deps.ts b/deps.ts index 5dd2e5d..390aed0 100644 --- a/deps.ts +++ b/deps.ts @@ -12,5 +12,7 @@ export { export type { MiddlewareHandler, MiddlewareHandlerContext, -} from "https://deno.land/x/fresh@1.6.0/server.ts"; + Plugin, + PluginMiddleware, +} from "https://deno.land/x/fresh@1.6.5/server.ts"; export { assertEquals } from "https://deno.land/std@0.208.0/testing/asserts.ts"; diff --git a/src/plugins/cookie_plugin.ts b/src/plugins/cookie_plugin.ts index 8d2ccc1..71d55a7 100644 --- a/src/plugins/cookie_plugin.ts +++ b/src/plugins/cookie_plugin.ts @@ -1,10 +1,11 @@ import { CookieFreshSessionOptions } from "../type.ts"; import { getCookieSessionHandler } from "../handlers/cookie_handler.ts"; +import { Plugin } from "../../deps.ts"; export function getCookieSessionPlugin( middlewarePath = "/", options?: CookieFreshSessionOptions, -) { +): Plugin> { const handler = getCookieSessionHandler(options); return { name: "CookieSessionPlugin", diff --git a/tests/config/cookie_session_test_plugin_fresh.config.ts b/tests/config/cookie_session_test_plugin_fresh.config.ts index 37aaaac..6249778 100644 --- a/tests/config/cookie_session_test_plugin_fresh.config.ts +++ b/tests/config/cookie_session_test_plugin_fresh.config.ts @@ -3,5 +3,8 @@ import { getCookieSessionPlugin } from "../../mod.ts"; import { testPlugin } from "../plugin/test_plugin.ts"; export default defineConfig({ - plugins: [getCookieSessionPlugin("/"), testPlugin], + plugins: [ + getCookieSessionPlugin("/"), + testPlugin, + ], });