mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-28 21:58:15 +02:00
Basic verify session breakout
This commit is contained in:
parent
fd605d9c81
commit
22545cac8b
2 changed files with 240 additions and 72 deletions
211
server/db/queries/verifySessionQueries.ts
Normal file
211
server/db/queries/verifySessionQueries.ts
Normal file
|
@ -0,0 +1,211 @@
|
|||
import { db } from "@server/db";
|
||||
import {
|
||||
Resource,
|
||||
ResourcePassword,
|
||||
ResourcePincode,
|
||||
ResourceRule,
|
||||
resourcePassword,
|
||||
resourcePincode,
|
||||
resourceRules,
|
||||
resources,
|
||||
roleResources,
|
||||
sessions,
|
||||
userOrgs,
|
||||
userResources,
|
||||
users
|
||||
} from "@server/db";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import axios from "axios";
|
||||
|
||||
export type ResourceWithAuth = {
|
||||
resource: Resource | null;
|
||||
pincode: ResourcePincode | null;
|
||||
password: ResourcePassword | null;
|
||||
};
|
||||
|
||||
export type UserSessionWithUser = {
|
||||
session: any;
|
||||
user: any;
|
||||
};
|
||||
|
||||
const MODE = "remote";
|
||||
const remoteEndpoint = "https://api.example.com";
|
||||
|
||||
/**
|
||||
* Get resource by domain with pincode and password information
|
||||
*/
|
||||
export async function getResourceByDomain(
|
||||
domain: string
|
||||
): Promise<ResourceWithAuth | null> {
|
||||
if (MODE === "remote") {
|
||||
try {
|
||||
const response = await axios.get(`${remoteEndpoint}/resource/domain/${domain}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching resource by domain:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const [result] = await db
|
||||
.select()
|
||||
.from(resources)
|
||||
.leftJoin(
|
||||
resourcePincode,
|
||||
eq(resourcePincode.resourceId, resources.resourceId)
|
||||
)
|
||||
.leftJoin(
|
||||
resourcePassword,
|
||||
eq(resourcePassword.resourceId, resources.resourceId)
|
||||
)
|
||||
.where(eq(resources.fullDomain, domain))
|
||||
.limit(1);
|
||||
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
resource: result.resources,
|
||||
pincode: result.resourcePincode,
|
||||
password: result.resourcePassword
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user session with user information
|
||||
*/
|
||||
export async function getUserSessionWithUser(
|
||||
userSessionId: string
|
||||
): Promise<UserSessionWithUser | null> {
|
||||
if (MODE === "remote") {
|
||||
try {
|
||||
const response = await axios.get(`${remoteEndpoint}/session/${userSessionId}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching user session:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const [res] = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.leftJoin(users, eq(users.userId, sessions.userId))
|
||||
.where(eq(sessions.sessionId, userSessionId));
|
||||
|
||||
if (!res) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
session: res.session,
|
||||
user: res.user
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user organization role
|
||||
*/
|
||||
export async function getUserOrgRole(userId: string, orgId: string) {
|
||||
if (MODE === "remote") {
|
||||
try {
|
||||
const response = await axios.get(`${remoteEndpoint}/user/${userId}/org/${orgId}/role`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching user org role:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const userOrgRole = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, userId),
|
||||
eq(userOrgs.orgId, orgId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
return userOrgRole.length > 0 ? userOrgRole[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if role has access to resource
|
||||
*/
|
||||
export async function getRoleResourceAccess(resourceId: number, roleId: number) {
|
||||
if (MODE === "remote") {
|
||||
try {
|
||||
const response = await axios.get(`${remoteEndpoint}/role/${roleId}/resource/${resourceId}/access`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching role resource access:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const roleResourceAccess = await db
|
||||
.select()
|
||||
.from(roleResources)
|
||||
.where(
|
||||
and(
|
||||
eq(roleResources.resourceId, resourceId),
|
||||
eq(roleResources.roleId, roleId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
return roleResourceAccess.length > 0 ? roleResourceAccess[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has direct access to resource
|
||||
*/
|
||||
export async function getUserResourceAccess(userId: string, resourceId: number) {
|
||||
if (MODE === "remote") {
|
||||
try {
|
||||
const response = await axios.get(`${remoteEndpoint}/user/${userId}/resource/${resourceId}/access`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching user resource access:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const userResourceAccess = await db
|
||||
.select()
|
||||
.from(userResources)
|
||||
.where(
|
||||
and(
|
||||
eq(userResources.userId, userId),
|
||||
eq(userResources.resourceId, resourceId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
return userResourceAccess.length > 0 ? userResourceAccess[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resource rules for a given resource
|
||||
*/
|
||||
export async function getResourceRules(resourceId: number): Promise<ResourceRule[]> {
|
||||
if (MODE === "remote") {
|
||||
try {
|
||||
const response = await axios.get(`${remoteEndpoint}/resource/${resourceId}/rules`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching resource rules:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const rules = await db
|
||||
.select()
|
||||
.from(resourceRules)
|
||||
.where(eq(resourceRules.resourceId, resourceId));
|
||||
|
||||
return rules;
|
||||
}
|
|
@ -6,20 +6,21 @@ import {
|
|||
} from "@server/auth/sessions/resource";
|
||||
import { verifyResourceAccessToken } from "@server/auth/verifyResourceAccessToken";
|
||||
import { db } from "@server/db";
|
||||
import {
|
||||
getResourceByDomain,
|
||||
getUserSessionWithUser,
|
||||
getUserOrgRole,
|
||||
getRoleResourceAccess,
|
||||
getUserResourceAccess,
|
||||
getResourceRules
|
||||
} from "@server/db/queries/verifySessionQueries";
|
||||
import {
|
||||
Resource,
|
||||
ResourceAccessToken,
|
||||
ResourcePassword,
|
||||
resourcePassword,
|
||||
ResourcePincode,
|
||||
resourcePincode,
|
||||
ResourceRule,
|
||||
resourceRules,
|
||||
resources,
|
||||
roleResources,
|
||||
sessions,
|
||||
userOrgs,
|
||||
userResources,
|
||||
users
|
||||
} from "@server/db";
|
||||
import config from "@server/lib/config";
|
||||
|
@ -27,7 +28,6 @@ import { isIpInCidr } from "@server/lib/ip";
|
|||
import { response } from "@server/lib/response";
|
||||
import logger from "@server/logger";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import NodeCache from "node-cache";
|
||||
|
@ -137,31 +137,14 @@ export async function verifyResourceSession(
|
|||
| undefined = cache.get(resourceCacheKey);
|
||||
|
||||
if (!resourceData) {
|
||||
const [result] = await db
|
||||
.select()
|
||||
.from(resources)
|
||||
.leftJoin(
|
||||
resourcePincode,
|
||||
eq(resourcePincode.resourceId, resources.resourceId)
|
||||
)
|
||||
.leftJoin(
|
||||
resourcePassword,
|
||||
eq(resourcePassword.resourceId, resources.resourceId)
|
||||
)
|
||||
.where(eq(resources.fullDomain, cleanHost))
|
||||
.limit(1);
|
||||
const result = await getResourceByDomain(cleanHost);
|
||||
|
||||
if (!result) {
|
||||
logger.debug("Resource not found", cleanHost);
|
||||
return notAllowed(res);
|
||||
}
|
||||
|
||||
resourceData = {
|
||||
resource: result.resources,
|
||||
pincode: result.resourcePincode,
|
||||
password: result.resourcePassword
|
||||
};
|
||||
|
||||
resourceData = result;
|
||||
cache.set(resourceCacheKey, resourceData);
|
||||
}
|
||||
|
||||
|
@ -529,14 +512,13 @@ async function isUserAllowedToAccessResource(
|
|||
userSessionId: string,
|
||||
resource: Resource
|
||||
): Promise<BasicUserData | null> {
|
||||
const [res] = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.leftJoin(users, eq(users.userId, sessions.userId))
|
||||
.where(eq(sessions.sessionId, userSessionId));
|
||||
const result = await getUserSessionWithUser(userSessionId);
|
||||
|
||||
const user = res.user;
|
||||
const session = res.session;
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { user, session } = result;
|
||||
|
||||
if (!user || !session) {
|
||||
return null;
|
||||
|
@ -549,33 +531,18 @@ async function isUserAllowedToAccessResource(
|
|||
return null;
|
||||
}
|
||||
|
||||
const userOrgRole = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, user.userId),
|
||||
eq(userOrgs.orgId, resource.orgId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
const userOrgRole = await getUserOrgRole(user.userId, resource.orgId);
|
||||
|
||||
if (userOrgRole.length === 0) {
|
||||
if (!userOrgRole) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const roleResourceAccess = await db
|
||||
.select()
|
||||
.from(roleResources)
|
||||
.where(
|
||||
and(
|
||||
eq(roleResources.resourceId, resource.resourceId),
|
||||
eq(roleResources.roleId, userOrgRole[0].roleId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
const roleResourceAccess = await getRoleResourceAccess(
|
||||
resource.resourceId,
|
||||
userOrgRole.roleId
|
||||
);
|
||||
|
||||
if (roleResourceAccess.length > 0) {
|
||||
if (roleResourceAccess) {
|
||||
return {
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
|
@ -583,18 +550,12 @@ async function isUserAllowedToAccessResource(
|
|||
};
|
||||
}
|
||||
|
||||
const userResourceAccess = await db
|
||||
.select()
|
||||
.from(userResources)
|
||||
.where(
|
||||
and(
|
||||
eq(userResources.userId, user.userId),
|
||||
eq(userResources.resourceId, resource.resourceId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
const userResourceAccess = await getUserResourceAccess(
|
||||
user.userId,
|
||||
resource.resourceId
|
||||
);
|
||||
|
||||
if (userResourceAccess.length > 0) {
|
||||
if (userResourceAccess) {
|
||||
return {
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
|
@ -615,11 +576,7 @@ async function checkRules(
|
|||
let rules: ResourceRule[] | undefined = cache.get(ruleCacheKey);
|
||||
|
||||
if (!rules) {
|
||||
rules = await db
|
||||
.select()
|
||||
.from(resourceRules)
|
||||
.where(eq(resourceRules.resourceId, resourceId));
|
||||
|
||||
rules = await getResourceRules(resourceId);
|
||||
cache.set(ruleCacheKey, rules);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue