mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-02 17:14:55 +02:00
refactor auth to work cross domain and with http resources closes #100
This commit is contained in:
parent
6050a0a7d7
commit
9f1f2910e4
27 changed files with 688 additions and 201 deletions
|
@ -3,7 +3,13 @@ import {
|
|||
encodeHexLowerCase
|
||||
} from "@oslojs/encoding";
|
||||
import { sha256 } from "@oslojs/crypto/sha2";
|
||||
import { Session, sessions, User, users } from "@server/db/schema";
|
||||
import {
|
||||
resourceSessions,
|
||||
Session,
|
||||
sessions,
|
||||
User,
|
||||
users
|
||||
} from "@server/db/schema";
|
||||
import db from "@server/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import config from "@server/lib/config";
|
||||
|
@ -13,9 +19,14 @@ import logger from "@server/logger";
|
|||
|
||||
export const SESSION_COOKIE_NAME =
|
||||
config.getRawConfig().server.session_cookie_name;
|
||||
export const SESSION_COOKIE_EXPIRES = 1000 * 60 * 60 * 24 * 30;
|
||||
export const SESSION_COOKIE_EXPIRES =
|
||||
1000 *
|
||||
60 *
|
||||
60 *
|
||||
config.getRawConfig().server.dashboard_session_length_hours;
|
||||
export const SECURE_COOKIES = config.getRawConfig().server.secure_cookies;
|
||||
export const COOKIE_DOMAIN = "." + config.getBaseDomain();
|
||||
export const COOKIE_DOMAIN =
|
||||
"." + new URL(config.getRawConfig().app.dashboard_url).hostname;
|
||||
|
||||
export function generateSessionToken(): string {
|
||||
const bytes = new Uint8Array(20);
|
||||
|
@ -65,12 +76,21 @@ export async function validateSessionToken(
|
|||
session.expiresAt = new Date(
|
||||
Date.now() + SESSION_COOKIE_EXPIRES
|
||||
).getTime();
|
||||
await db
|
||||
.update(sessions)
|
||||
.set({
|
||||
expiresAt: session.expiresAt
|
||||
})
|
||||
.where(eq(sessions.sessionId, session.sessionId));
|
||||
await db.transaction(async (trx) => {
|
||||
await trx
|
||||
.update(sessions)
|
||||
.set({
|
||||
expiresAt: session.expiresAt
|
||||
})
|
||||
.where(eq(sessions.sessionId, session.sessionId));
|
||||
|
||||
await trx
|
||||
.update(resourceSessions)
|
||||
.set({
|
||||
expiresAt: session.expiresAt
|
||||
})
|
||||
.where(eq(resourceSessions.userSessionId, session.sessionId));
|
||||
});
|
||||
}
|
||||
return { session, user };
|
||||
}
|
||||
|
@ -90,9 +110,9 @@ export function serializeSessionCookie(
|
|||
if (isSecure) {
|
||||
logger.debug("Setting cookie for secure origin");
|
||||
if (SECURE_COOKIES) {
|
||||
return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Strict; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Secure; Domain=${COOKIE_DOMAIN}`;
|
||||
return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Strict; Max-Age=${SESSION_COOKIE_EXPIRES / 1000}; Path=/; Secure; Domain=${COOKIE_DOMAIN}`;
|
||||
} else {
|
||||
return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Strict; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Domain=${COOKIE_DOMAIN}`;
|
||||
return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Strict; Max-Age=${SESSION_COOKIE_EXPIRES / 1000}; Path=/; Domain=${COOKIE_DOMAIN}`;
|
||||
}
|
||||
} else {
|
||||
return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Lax; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/;`;
|
||||
|
|
|
@ -6,19 +6,20 @@ import { eq, and } from "drizzle-orm";
|
|||
import config from "@server/lib/config";
|
||||
|
||||
export const SESSION_COOKIE_NAME =
|
||||
config.getRawConfig().server.resource_session_cookie_name;
|
||||
export const SESSION_COOKIE_EXPIRES = 1000 * 60 * 60 * 24 * 30;
|
||||
config.getRawConfig().server.session_cookie_name;
|
||||
export const SESSION_COOKIE_EXPIRES =
|
||||
1000 * 60 * 60 * config.getRawConfig().server.resource_session_length_hours;
|
||||
export const SECURE_COOKIES = config.getRawConfig().server.secure_cookies;
|
||||
export const COOKIE_DOMAIN = "." + config.getBaseDomain();
|
||||
|
||||
export async function createResourceSession(opts: {
|
||||
token: string;
|
||||
resourceId: number;
|
||||
passwordId?: number;
|
||||
pincodeId?: number;
|
||||
whitelistId?: number;
|
||||
accessTokenId?: string;
|
||||
usedOtp?: boolean;
|
||||
isRequestToken?: boolean;
|
||||
passwordId?: number | null;
|
||||
pincodeId?: number | null;
|
||||
userSessionId?: string | null;
|
||||
whitelistId?: number | null;
|
||||
accessTokenId?: string | null;
|
||||
doNotExtend?: boolean;
|
||||
expiresAt?: number | null;
|
||||
sessionLength?: number | null;
|
||||
|
@ -27,7 +28,8 @@ export async function createResourceSession(opts: {
|
|||
!opts.passwordId &&
|
||||
!opts.pincodeId &&
|
||||
!opts.whitelistId &&
|
||||
!opts.accessTokenId
|
||||
!opts.accessTokenId &&
|
||||
!opts.userSessionId
|
||||
) {
|
||||
throw new Error("Auth method must be provided");
|
||||
}
|
||||
|
@ -47,7 +49,9 @@ export async function createResourceSession(opts: {
|
|||
pincodeId: opts.pincodeId || null,
|
||||
whitelistId: opts.whitelistId || null,
|
||||
doNotExtend: opts.doNotExtend || false,
|
||||
accessTokenId: opts.accessTokenId || null
|
||||
accessTokenId: opts.accessTokenId || null,
|
||||
isRequestToken: opts.isRequestToken || false,
|
||||
userSessionId: opts.userSessionId || null
|
||||
};
|
||||
|
||||
await db.insert(resourceSessions).values(session);
|
||||
|
@ -162,22 +166,25 @@ export async function invalidateAllSessions(
|
|||
|
||||
export function serializeResourceSessionCookie(
|
||||
cookieName: string,
|
||||
token: string
|
||||
domain: string,
|
||||
token: string,
|
||||
isHttp: boolean = false
|
||||
): string {
|
||||
if (SECURE_COOKIES) {
|
||||
return `${cookieName}=${token}; HttpOnly; SameSite=Strict; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Secure; Domain=${COOKIE_DOMAIN}`;
|
||||
if (SECURE_COOKIES && !isHttp) {
|
||||
return `${cookieName}_s=${token}; HttpOnly; SameSite=Strict; Max-Age=${SESSION_COOKIE_EXPIRES / 1000}; Path=/; Secure; Domain=${"." + domain}`;
|
||||
} else {
|
||||
return `${cookieName}=${token}; HttpOnly; SameSite=Strict; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Domain=${COOKIE_DOMAIN}`;
|
||||
return `${cookieName}=${token}; HttpOnly; SameSite=Strict; Max-Age=${SESSION_COOKIE_EXPIRES / 1000}; Path=/; Domain=${"." + domain}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function createBlankResourceSessionTokenCookie(
|
||||
cookieName: string
|
||||
cookieName: string,
|
||||
domain: string
|
||||
): string {
|
||||
if (SECURE_COOKIES) {
|
||||
return `${cookieName}=; HttpOnly; SameSite=Strict; Max-Age=0; Path=/; Secure; Domain=${COOKIE_DOMAIN}`;
|
||||
return `${cookieName}_s=; HttpOnly; SameSite=Strict; Max-Age=0; Path=/; Secure; Domain=${"." + domain}`;
|
||||
} else {
|
||||
return `${cookieName}=; HttpOnly; SameSite=Strict; Max-Age=0; Path=/; Domain=${COOKIE_DOMAIN}`;
|
||||
return `${cookieName}=; HttpOnly; SameSite=Strict; Max-Age=0; Path=/; Domain=${"." + domain}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue