cleanup
This commit is contained in:
@@ -5,7 +5,7 @@ import LikeIcon from "~/components/icons/LikeIcon";
|
||||
export interface PostLike {
|
||||
id: number;
|
||||
user_id: string;
|
||||
post_id: string;
|
||||
post_id: number;
|
||||
}
|
||||
|
||||
export interface AuthenticatedLikeProps {
|
||||
@@ -36,15 +36,15 @@ export default function AuthenticatedLike(props: AuthenticatedLikeProps) {
|
||||
if (initialHasLiked) {
|
||||
const result = await api.database.removePostLike.mutate({
|
||||
user_id: props.currentUserID,
|
||||
post_id: props.projectID.toString()
|
||||
post_id: props.projectID
|
||||
});
|
||||
setLikes(result.newLikes as PostLike[]);
|
||||
setLikes(result.newLikes as unknown as PostLike[]);
|
||||
} else {
|
||||
const result = await api.database.addPostLike.mutate({
|
||||
user_id: props.currentUserID,
|
||||
post_id: props.projectID.toString()
|
||||
post_id: props.projectID
|
||||
});
|
||||
setLikes(result.newLikes as PostLike[]);
|
||||
setLikes(result.newLikes as unknown as PostLike[]);
|
||||
}
|
||||
setInstantOffset(0);
|
||||
} catch (error) {
|
||||
|
||||
@@ -6,7 +6,8 @@ import type {
|
||||
UserPublicData,
|
||||
ReactionType,
|
||||
ModificationType,
|
||||
SortingMode
|
||||
SortingMode,
|
||||
CommentSectionProps
|
||||
} from "~/types/comment";
|
||||
import CommentInputBlock from "./CommentInputBlock";
|
||||
import CommentSortingSelect from "./CommentSortingSelect";
|
||||
|
||||
@@ -20,6 +20,7 @@ export default function DeletePostButton(props: DeletePostButtonProps) {
|
||||
await api.database.deletePost.mutate({ id: props.postID });
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error("Failed to delete post:", error);
|
||||
alert("Failed to delete post");
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -271,11 +271,12 @@ export default function PostBodyClient(props: PostBodyClientProps) {
|
||||
const headings = contentRef.querySelectorAll<HTMLElement>("h2");
|
||||
let referencesSection: HTMLElement | null = null;
|
||||
|
||||
headings.forEach((heading) => {
|
||||
for (const heading of headings) {
|
||||
if (heading.textContent?.trim() === referencesHeadingText) {
|
||||
referencesSection = heading;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (referencesSection) {
|
||||
referencesSection.className = "text-2xl font-bold mb-4 text-text";
|
||||
@@ -285,7 +286,7 @@ export default function PostBodyClient(props: PostBodyClientProps) {
|
||||
parentDiv.classList.add("references-heading");
|
||||
}
|
||||
|
||||
let currentElement = referencesSection.nextElementSibling;
|
||||
let currentElement: Element | null = referencesSection.nextElementSibling;
|
||||
|
||||
while (currentElement) {
|
||||
if (currentElement.tagName === "P") {
|
||||
|
||||
@@ -22,7 +22,7 @@ interface PostFormProps {
|
||||
published: boolean;
|
||||
tags: string[];
|
||||
};
|
||||
userID: number;
|
||||
userID: string;
|
||||
}
|
||||
|
||||
export default function PostForm(props: PostFormProps) {
|
||||
@@ -89,7 +89,7 @@ export default function PostForm(props: PostFormProps) {
|
||||
tags: null,
|
||||
author_id: props.userID
|
||||
});
|
||||
const newId = result.data as number;
|
||||
const newId = Number(result.data);
|
||||
setCreatedPostId(newId);
|
||||
setHasSaved(true);
|
||||
return newId;
|
||||
|
||||
79
src/lib/auth-callback-utils.ts
Normal file
79
src/lib/auth-callback-utils.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { APIEvent } from "@solidjs/start/server";
|
||||
import { createServerCaller } from "~/server/api/root";
|
||||
|
||||
/**
|
||||
* Result from an auth callback tRPC procedure
|
||||
*/
|
||||
interface AuthCallbackResult {
|
||||
success: boolean;
|
||||
redirectTo?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a successful auth callback result by redirecting
|
||||
*/
|
||||
export function redirectSuccess(result: AuthCallbackResult) {
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: result.redirectTo || "/account" }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to login with an error parameter
|
||||
*/
|
||||
export function redirectError(error: string) {
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: `/login?error=${encodeURIComponent(error)}` }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tRPC CONFLICT error (email already in use)
|
||||
*/
|
||||
export function isConflictError(error: unknown): boolean {
|
||||
return (
|
||||
error != null &&
|
||||
typeof error === "object" &&
|
||||
"code" in error &&
|
||||
(error as { code: string }).code === "CONFLICT"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an auth callback handler that calls a tRPC procedure and redirects
|
||||
*/
|
||||
export function createAuthCallbackHandler<Params extends object>(
|
||||
procedureName: string,
|
||||
callProcedure: (
|
||||
caller: ReturnType<typeof createServerCaller> extends Promise<infer T>
|
||||
? T
|
||||
: never,
|
||||
params: Params
|
||||
) => Promise<AuthCallbackResult>,
|
||||
handleError?: (error: unknown) => Response
|
||||
) {
|
||||
return async (event: APIEvent, params: Params) => {
|
||||
try {
|
||||
const caller = await createServerCaller(event);
|
||||
const result = await callProcedure(caller, params);
|
||||
|
||||
if (result.success) {
|
||||
return redirectSuccess(result);
|
||||
}
|
||||
|
||||
return redirectError("auth_failed");
|
||||
} catch (error) {
|
||||
if (handleError) {
|
||||
return handleError(error);
|
||||
}
|
||||
|
||||
if (isConflictError(error)) {
|
||||
return redirectError("email_in_use");
|
||||
}
|
||||
|
||||
return redirectError("server_error");
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { env } from "~/env/server";
|
||||
*
|
||||
* URL: https://freno.me/api/Gaze/appcast.xml
|
||||
*/
|
||||
export async function GET(event: APIEvent) {
|
||||
export async function GET(_event: APIEvent) {
|
||||
const bucket = env.VITE_DOWNLOAD_BUCKET_STRING;
|
||||
const key = "api/Gaze/appcast.xml";
|
||||
|
||||
@@ -47,7 +47,7 @@ export async function GET(event: APIEvent) {
|
||||
headers: {
|
||||
"Content-Type": "application/xml; charset=utf-8",
|
||||
"Cache-Control": "public, max-age=300", // Cache for 5 minutes
|
||||
"Access-Control-Allow-Origin": "*" // Allow CORS for appcast
|
||||
"Access-Control-Allow-Origin": "*" // Allow CORS for Sparkle appcast
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { env } from "~/env/server";
|
||||
*
|
||||
* URL: https://freno.me/api/InputHalo/appcast.xml
|
||||
*/
|
||||
export async function GET(event: APIEvent) {
|
||||
export async function GET(_event: APIEvent) {
|
||||
const bucket = env.VITE_DOWNLOAD_BUCKET_STRING;
|
||||
const key = "api/InputHalo/appcast.xml";
|
||||
|
||||
@@ -47,7 +47,7 @@ export async function GET(event: APIEvent) {
|
||||
headers: {
|
||||
"Content-Type": "application/xml; charset=utf-8",
|
||||
"Cache-Control": "public, max-age=300", // Cache for 5 minutes
|
||||
"Access-Control-Allow-Origin": "*" // Allow CORS for appcast
|
||||
"Access-Control-Allow-Origin": "*" // Allow CORS for Sparkle appcast
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,86 +1,26 @@
|
||||
import type { APIEvent } from "@solidjs/start/server";
|
||||
import { createServerCaller } from "~/server/api/root";
|
||||
import {
|
||||
createAuthCallbackHandler,
|
||||
redirectError
|
||||
} from "~/lib/auth-callback-utils";
|
||||
|
||||
export async function GET(event: APIEvent) {
|
||||
const url = new URL(event.request.url);
|
||||
const code = url.searchParams.get("code");
|
||||
const error = url.searchParams.get("error");
|
||||
|
||||
console.log("[GitHub OAuth Callback] Request received:", {
|
||||
hasCode: !!code,
|
||||
codeLength: code?.length,
|
||||
error
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error("[GitHub OAuth Callback] OAuth error from provider:", error);
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: `/login?error=${encodeURIComponent(error)}` }
|
||||
});
|
||||
return redirectError(error);
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
console.error("[GitHub OAuth Callback] Missing authorization code");
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=missing_code" }
|
||||
});
|
||||
return redirectError("missing_code");
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("[GitHub OAuth Callback] Creating tRPC caller...");
|
||||
const caller = await createServerCaller(event);
|
||||
const handler = createAuthCallbackHandler<{ code: string }>(
|
||||
"githubCallback",
|
||||
(caller, params) => caller.auth.githubCallback(params)
|
||||
);
|
||||
|
||||
console.log("[GitHub OAuth Callback] Calling githubCallback procedure...");
|
||||
const result = await caller.auth.githubCallback({ code });
|
||||
|
||||
console.log("[GitHub OAuth Callback] Result:", result);
|
||||
|
||||
if (result.success) {
|
||||
console.log(
|
||||
"[GitHub OAuth Callback] Login successful, redirecting to:",
|
||||
result.redirectTo
|
||||
);
|
||||
|
||||
// Auth handler already set cookie headers
|
||||
// Just redirect - the cookies are already in the response
|
||||
const redirectUrl = result.redirectTo || "/account";
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: redirectUrl }
|
||||
});
|
||||
} else {
|
||||
console.error(
|
||||
"[GitHub OAuth Callback] Login failed (result.success=false)"
|
||||
);
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=auth_failed" }
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[GitHub OAuth Callback] Error caught:", error);
|
||||
|
||||
if (error && typeof error === "object" && "code" in error) {
|
||||
const trpcError = error as { code: string; message?: string };
|
||||
|
||||
console.error("[GitHub OAuth Callback] tRPC error:", {
|
||||
code: trpcError.code,
|
||||
message: trpcError.message
|
||||
});
|
||||
|
||||
if (trpcError.code === "CONFLICT") {
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=email_in_use" }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=server_error" }
|
||||
});
|
||||
}
|
||||
return handler(event, { code });
|
||||
}
|
||||
|
||||
@@ -1,86 +1,26 @@
|
||||
import type { APIEvent } from "@solidjs/start/server";
|
||||
import { createServerCaller } from "~/server/api/root";
|
||||
import {
|
||||
createAuthCallbackHandler,
|
||||
redirectError
|
||||
} from "~/lib/auth-callback-utils";
|
||||
|
||||
export async function GET(event: APIEvent) {
|
||||
const url = new URL(event.request.url);
|
||||
const code = url.searchParams.get("code");
|
||||
const error = url.searchParams.get("error");
|
||||
|
||||
console.log("[Google OAuth Callback] Request received:", {
|
||||
hasCode: !!code,
|
||||
codeLength: code?.length,
|
||||
error
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error("[Google OAuth Callback] OAuth error from provider:", error);
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: `/login?error=${encodeURIComponent(error)}` }
|
||||
});
|
||||
return redirectError(error);
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
console.error("[Google OAuth Callback] Missing authorization code");
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=missing_code" }
|
||||
});
|
||||
return redirectError("missing_code");
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("[Google OAuth Callback] Creating tRPC caller...");
|
||||
const caller = await createServerCaller(event);
|
||||
const handler = createAuthCallbackHandler<{ code: string }>(
|
||||
"googleCallback",
|
||||
(caller, params) => caller.auth.googleCallback(params)
|
||||
);
|
||||
|
||||
console.log("[Google OAuth Callback] Calling googleCallback procedure...");
|
||||
const result = await caller.auth.googleCallback({ code });
|
||||
|
||||
console.log("[Google OAuth Callback] Result:", result);
|
||||
|
||||
if (result.success) {
|
||||
console.log(
|
||||
"[Google OAuth Callback] Login successful, redirecting to:",
|
||||
result.redirectTo
|
||||
);
|
||||
|
||||
// Auth handler already set cookie headers
|
||||
// Just redirect - the cookies are already in the response
|
||||
const redirectUrl = result.redirectTo || "/account";
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: redirectUrl }
|
||||
});
|
||||
} else {
|
||||
console.error(
|
||||
"[Google OAuth Callback] Login failed (result.success=false)"
|
||||
);
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=auth_failed" }
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Google OAuth Callback] Error caught:", error);
|
||||
|
||||
if (error && typeof error === "object" && "code" in error) {
|
||||
const trpcError = error as { code: string; message?: string };
|
||||
|
||||
console.error("[Google OAuth Callback] tRPC error:", {
|
||||
code: trpcError.code,
|
||||
message: trpcError.message
|
||||
});
|
||||
|
||||
if (trpcError.code === "CONFLICT") {
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=email_in_use" }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=server_error" }
|
||||
});
|
||||
}
|
||||
return handler(event, { code });
|
||||
}
|
||||
|
||||
@@ -1,86 +1,32 @@
|
||||
import type { APIEvent } from "@solidjs/start/server";
|
||||
import { createServerCaller } from "~/server/api/root";
|
||||
import {
|
||||
createAuthCallbackHandler,
|
||||
redirectError
|
||||
} from "~/lib/auth-callback-utils";
|
||||
|
||||
export async function GET(event: APIEvent) {
|
||||
const url = new URL(event.request.url);
|
||||
const email = url.searchParams.get("email");
|
||||
const token = url.searchParams.get("token");
|
||||
|
||||
console.log("[Email Login Callback] Request received:", {
|
||||
email,
|
||||
hasToken: !!token,
|
||||
tokenLength: token?.length
|
||||
});
|
||||
|
||||
if (!email || !token) {
|
||||
console.error("[Email Login Callback] Missing required parameters:", {
|
||||
hasEmail: !!email,
|
||||
hasToken: !!token
|
||||
});
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=missing_params" }
|
||||
});
|
||||
return redirectError("missing_params");
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("[Email Login Callback] Creating tRPC caller...");
|
||||
// Create tRPC caller to invoke the emailLogin procedure
|
||||
const caller = await createServerCaller(event);
|
||||
|
||||
console.log("[Email Login Callback] Calling emailLogin procedure...");
|
||||
// Call the email login handler - rememberMe will be read from JWT payload
|
||||
const result = await caller.auth.emailLogin({
|
||||
email,
|
||||
token
|
||||
});
|
||||
|
||||
console.log("[Email Login Callback] Login result:", result);
|
||||
|
||||
if (result.success) {
|
||||
console.log(
|
||||
"[Email Login Callback] Login successful, redirecting to:",
|
||||
result.redirectTo
|
||||
);
|
||||
|
||||
// Auth handler already set cookie headers
|
||||
// Just redirect - the cookies are already in the response
|
||||
const redirectUrl = result.redirectTo || "/account";
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: redirectUrl }
|
||||
});
|
||||
} else {
|
||||
console.error(
|
||||
"[Email Login Callback] Login failed (result.success=false)"
|
||||
);
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { Location: "/login?error=auth_failed" }
|
||||
});
|
||||
const handler = createAuthCallbackHandler<{
|
||||
email: string;
|
||||
token: string;
|
||||
}>(
|
||||
"emailLogin",
|
||||
(caller, params) => caller.auth.emailLogin(params),
|
||||
(error) => {
|
||||
// Check for token expiration
|
||||
const message = error instanceof Error ? error.message : "";
|
||||
const isTokenError =
|
||||
message.includes("expired") || message.includes("invalid");
|
||||
return redirectError(isTokenError ? "link_expired" : "server_error");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Email Login Callback] Error caught:", error);
|
||||
);
|
||||
|
||||
// Check if it's a token expiration error
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "server_error";
|
||||
const isTokenError =
|
||||
errorMessage.includes("expired") || errorMessage.includes("invalid");
|
||||
|
||||
console.error("[Email Login Callback] Error details:", {
|
||||
errorMessage,
|
||||
isTokenError,
|
||||
errorType: error instanceof Error ? error.constructor.name : typeof error
|
||||
});
|
||||
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: {
|
||||
Location: isTokenError
|
||||
? "/login?error=link_expired"
|
||||
: "/login?error=server_error"
|
||||
}
|
||||
});
|
||||
}
|
||||
return handler(event, { email, token });
|
||||
}
|
||||
|
||||
@@ -155,7 +155,9 @@ export const reactionTypeSchema = z.enum([
|
||||
"moneyEye",
|
||||
"sick",
|
||||
"upsideDown",
|
||||
"worried"
|
||||
"worried",
|
||||
"upVote",
|
||||
"downVote"
|
||||
]);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { H3Event } from "vinxi/http";
|
||||
import { getCookie, setCookie } from "vinxi/http";
|
||||
import { getCookie, setCookie, getHeader } from "vinxi/http";
|
||||
import { OAuth2Client } from "google-auth-library";
|
||||
import type { Row } from "@libsql/client/web";
|
||||
import { SignJWT, jwtVerify } from "jose";
|
||||
import { env } from "~/env/server";
|
||||
import { ConnectionFactory } from "./database";
|
||||
import { ConnectionFactory } from "./db-connections";
|
||||
import { AUTH_CONFIG, expiryToSeconds, getAccessTokenExpiry } from "~/config";
|
||||
|
||||
export const authCookieName = "auth_token";
|
||||
@@ -30,7 +30,7 @@ function getAuthCookieOptions(rememberMe: boolean) {
|
||||
}
|
||||
|
||||
function getAuthHeaderToken(event: H3Event): string | null {
|
||||
const requestHeader = event.request?.headers?.get?.("authorization") || null;
|
||||
const requestHeader = getHeader(event, "authorization") || null;
|
||||
const eventHeader = event.headers
|
||||
? typeof (event.headers as any).get === "function"
|
||||
? (event.headers as any).get("authorization")
|
||||
@@ -199,6 +199,7 @@ export async function validateLineageRequest({
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to verify email auth token:", err);
|
||||
return false;
|
||||
}
|
||||
} else if (provider == "apple") {
|
||||
|
||||
@@ -11,43 +11,13 @@ import {
|
||||
TimeoutError,
|
||||
APIError
|
||||
} from "~/server/fetch-utils";
|
||||
|
||||
let mainDBConnection: ReturnType<typeof createClient> | null = null;
|
||||
let lineageDBConnection: ReturnType<typeof createClient> | null = null;
|
||||
let nessaDBConnection: ReturnType<typeof createClient> | null = null;
|
||||
|
||||
export function ConnectionFactory() {
|
||||
if (!mainDBConnection) {
|
||||
const config = {
|
||||
url: env.TURSO_DB_URL,
|
||||
authToken: env.TURSO_DB_TOKEN
|
||||
};
|
||||
mainDBConnection = createClient(config);
|
||||
}
|
||||
return mainDBConnection;
|
||||
}
|
||||
|
||||
export function LineageConnectionFactory() {
|
||||
if (!lineageDBConnection) {
|
||||
const config = {
|
||||
url: env.TURSO_LINEAGE_URL,
|
||||
authToken: env.TURSO_LINEAGE_TOKEN
|
||||
};
|
||||
lineageDBConnection = createClient(config);
|
||||
}
|
||||
return lineageDBConnection;
|
||||
}
|
||||
|
||||
export function NessaConnectionFactory() {
|
||||
if (!nessaDBConnection) {
|
||||
const config = {
|
||||
url: env.NESSA_DB_URL,
|
||||
authToken: env.NESSA_DB_TOKEN
|
||||
};
|
||||
nessaDBConnection = createClient(config);
|
||||
}
|
||||
return nessaDBConnection;
|
||||
}
|
||||
import {
|
||||
ConnectionFactory,
|
||||
LineageConnectionFactory,
|
||||
NessaConnectionFactory
|
||||
} from "~/server/db-connections";
|
||||
// Re-export connection factories to avoid circular import with auth.ts
|
||||
export { ConnectionFactory, LineageConnectionFactory, NessaConnectionFactory };
|
||||
|
||||
export async function LineageDBInit() {
|
||||
const turso = createAPIClient({
|
||||
@@ -209,7 +179,7 @@ export async function getUserBasicInfo(event: H3Event): Promise<{
|
||||
return { email: null, isAuthenticated: false };
|
||||
}
|
||||
|
||||
const user = res.rows[0] as { email: string | null };
|
||||
const user = res.rows[0] as unknown as { email: string | null };
|
||||
return {
|
||||
email: user.email,
|
||||
isAuthenticated: true
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import { defineMiddleware } from "vinxi/http";
|
||||
import { defineMiddleware, setHeaders } from "vinxi/http";
|
||||
|
||||
// Security headers middleware — sets CSP and hardening headers on all responses
|
||||
export default defineMiddleware((_event, next) => {
|
||||
return next().then((response) => {
|
||||
response.headers.set(
|
||||
"Content-Security-Policy",
|
||||
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"
|
||||
);
|
||||
response.headers.set("X-Content-Type-Options", "nosniff");
|
||||
response.headers.set("X-Frame-Options", "DENY");
|
||||
response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
|
||||
response.headers.set(
|
||||
"Permissions-Policy",
|
||||
"camera=(), microphone=(), geolocation=()"
|
||||
);
|
||||
return response;
|
||||
});
|
||||
export default defineMiddleware({
|
||||
onRequest: (event) => {
|
||||
setHeaders(event, {
|
||||
"Content-Security-Policy":
|
||||
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'",
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
"X-Frame-Options": "DENY",
|
||||
"Referrer-Policy": "strict-origin-when-cross-origin",
|
||||
"Permissions-Policy": "camera=(), microphone=(), geolocation=()"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -51,7 +51,12 @@ function getCookieValue(event: H3Event, name: string): string | undefined {
|
||||
try {
|
||||
const value = getCookie(event, name);
|
||||
if (value) return value;
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
"[security] getCookie failed, falling back to header parse:",
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const cookieHeader =
|
||||
|
||||
@@ -26,7 +26,9 @@ export type ReactionType =
|
||||
| "moneyEye"
|
||||
| "sick"
|
||||
| "upsideDown"
|
||||
| "worried";
|
||||
| "worried"
|
||||
| "upVote"
|
||||
| "downVote";
|
||||
|
||||
export interface UserPublicData {
|
||||
email?: string;
|
||||
|
||||
Reference in New Issue
Block a user