Skip to content

Commit faedc56

Browse files
authored
fix: authentication (#26)
1 parent f9dcd2b commit faedc56

File tree

7 files changed

+161
-173
lines changed

7 files changed

+161
-173
lines changed

.env.sample

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# NOTE: .env is only used for development.
22
# = credentials (if any)
3+
# == COOKIE_SIGN: 値に特に意味はないのでローカルでは適当な値を入れてください
4+
COOKIE_SIGN=randomly-generated-128-bytes-string
35

46
# = config
57
# == service config

service/db/schema.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
33
export const participants = sqliteTable("participants", {
44
id: text("id").notNull().primaryKey(),
55
name: text().notNull(),
6-
account_id: text("account_id").references(() => accounts.id).notNull(),
6+
browser_id: text("browser_id").notNull(),
77
project_id: text("project_id").references(() => projects.id).notNull(),
88
is_admin: integer("is_admin").notNull(),
99
});

service/features/auth/index.ts

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import type { Context } from "hono";
2+
import { getSignedCookie, setSignedCookie } from "hono/cookie";
3+
import { db } from "../../db/client.ts";
4+
import { accounts, type SelectAccount } from "../../db/schema.ts";
5+
import { HTTPException } from "hono/http-exception";
6+
import { eq } from "drizzle-orm";
7+
import type { CookieOptions } from "hono/utils/cookie";
8+
import { env } from "../../utils/env.ts";
9+
10+
function GET_COOKIE_SIGN(c: Context): string {
11+
return env(c, "COOKIE_SIGN");
12+
}
13+
14+
const cookie_identifier__browser_id = "howmatch.browser_id";
15+
// TODO: make it last forever or smth
16+
const cookieOptions: CookieOptions = {
17+
httpOnly: true,
18+
secure: false,
19+
};
20+
21+
type NoAuth = {
22+
name: string;
23+
};
24+
25+
// TODO: implement authentication
26+
type AuthInfo = {
27+
kind: "none";
28+
info: NoAuth;
29+
};
30+
31+
export async function signup(c: Context, auth: AuthInfo): Promise<SelectAccount> {
32+
const browser_id = await getBrowserID(c);
33+
const prev = await _findAccount(c, auth);
34+
if (prev) {
35+
// already has an account
36+
return prev;
37+
}
38+
const account = (
39+
await db(c)
40+
.insert(accounts)
41+
.values({
42+
id: crypto.randomUUID(),
43+
browser_id,
44+
name: auth.info.name,
45+
})
46+
.returning()
47+
)[0];
48+
if (!account) throw new HTTPException(500, { message: "Failed to create account" });
49+
return account;
50+
}
51+
52+
// TODO: implement authentication
53+
export async function login(c: Context, auth: AuthInfo): Promise<SelectAccount> {
54+
const acc = await _findAccount(c, auth);
55+
if (acc) {
56+
setSignedCookie(c, cookie_identifier__browser_id, acc.browser_id, GET_COOKIE_SIGN(c), cookieOptions);
57+
return acc;
58+
}
59+
throw new HTTPException(404, { message: "account not found" });
60+
}
61+
62+
// creates new one if necessary.
63+
export async function getBrowserID(c: Context): Promise<string> {
64+
const cookie = await getSignedCookie(c, GET_COOKIE_SIGN(c), cookie_identifier__browser_id);
65+
if (cookie) {
66+
return cookie;
67+
}
68+
const browser_id = crypto.randomUUID();
69+
await setSignedCookie(c, cookie_identifier__browser_id, browser_id, GET_COOKIE_SIGN(c), cookieOptions);
70+
return browser_id;
71+
}
72+
73+
// TODO: implement authentication
74+
async function _findAccount(c: Context, auth: AuthInfo): Promise<SelectAccount | undefined> {
75+
switch (auth.kind) {
76+
case "none": {
77+
const accountsResult = await db(c)
78+
.select()
79+
.from(accounts)
80+
.where(eq(accounts.name, auth.info.name))
81+
.limit(1);
82+
return accountsResult[0]; // findUnique をしたかった
83+
}
84+
default:
85+
auth.kind satisfies never;
86+
}
87+
}

service/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const app = new Hono<HonoOptions>()
99
.use(
1010
"/*",
1111
async (c, next) => {
12-
const CORS_ALLOW_ORIGINS = env(c, "CORS_ALLOW_ORIGINS", "");
12+
const CORS_ALLOW_ORIGINS = env(c, "CORS_ALLOW_ORIGINS", { fallback: "" });
1313
return await cors({
1414
origin: CORS_ALLOW_ORIGINS.split(","),
1515
credentials: true,

0 commit comments

Comments
 (0)