fix npm run build

This commit is contained in:
Rayyan
2026-08-02 20:01:29 +07:00
parent 306c145f91
commit eb6031282a
236 changed files with 5557 additions and 47 deletions
+110
View File
@@ -0,0 +1,110 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthController = void 0;
const common_1 = require("@nestjs/common");
const swagger_1 = require("@nestjs/swagger");
const auth_service_1 = require("./auth.service");
let AuthController = class AuthController {
authService;
constructor(authService) {
this.authService = authService;
}
async login(returnTo, res) {
const redirect = await this.authService.createAuthorizationRedirect(returnTo);
return res.redirect(302, redirect);
}
async callback(code, state, res) {
const result = await this.authService.handleCallback(code, state);
// set cookies
const cookieOptions = {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/',
};
// access token cookie (internal JWT)
res.cookie('raylab_jwt', result.accessToken, { ...cookieOptions, maxAge: result.expiresIn * 1000 });
// refresh token cookie
res.cookie('raylab_refresh', result.refreshToken, { ...cookieOptions, maxAge: result.refreshTtl * 1000 });
return res.redirect(302, result.returnTo || '/');
}
async logout(req, res) {
const refreshToken = req.cookies?.raylab_refresh || req.body?.refreshToken;
const redirect = await this.authService.logout(refreshToken);
return res.redirect(302, redirect);
}
async refresh(req) {
const refreshToken = req.cookies?.raylab_refresh || req.body?.refreshToken;
const result = await this.authService.refresh(refreshToken);
return { success: true, data: result };
}
async me(req) {
const token = (req.cookies?.raylab_jwt) || (req.headers.authorization && req.headers.authorization.replace(/^Bearer\s+/i, ''));
const user = await this.authService.me(token);
return { success: true, data: user };
}
};
exports.AuthController = AuthController;
__decorate([
(0, common_1.Get)('login'),
(0, swagger_1.ApiOperation)({ summary: 'Start Authorization Code + PKCE login (redirect to Identity Provider)' }),
__param(0, (0, common_1.Query)('returnTo')),
__param(1, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "login", null);
__decorate([
(0, common_1.Get)('callback'),
(0, swagger_1.ApiOperation)({ summary: 'OIDC callback endpoint' }),
__param(0, (0, common_1.Query)('code')),
__param(1, (0, common_1.Query)('state')),
__param(2, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String, Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "callback", null);
__decorate([
(0, common_1.Post)('logout'),
(0, common_1.HttpCode)(common_1.HttpStatus.OK),
(0, swagger_1.ApiOperation)({ summary: 'Logout (invalidate internal session and redirect to identity provider logout)' }),
__param(0, (0, common_1.Req)()),
__param(1, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "logout", null);
__decorate([
(0, common_1.Post)('refresh'),
(0, swagger_1.ApiOperation)({ summary: 'Refresh internal JWT using internal refresh token' }),
__param(0, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "refresh", null);
__decorate([
(0, common_1.Get)('me'),
(0, swagger_1.ApiOperation)({ summary: 'Get current user from internal JWT (cookie or Authorization header)' }),
__param(0, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "me", null);
exports.AuthController = AuthController = __decorate([
(0, swagger_1.ApiTags)('Auth'),
(0, common_1.Controller)('auth'),
__metadata("design:paramtypes", [auth_service_1.AuthService])
], AuthController);
//# sourceMappingURL=auth.controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.controller.ts"],"names":[],"mappings":"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"}
+75
View File
@@ -0,0 +1,75 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthModule = void 0;
const common_1 = require("@nestjs/common");
const auth_controller_1 = require("./auth.controller");
const auth_service_1 = require("./auth.service");
const config_1 = require("@nestjs/config");
const jwt_1 = require("@nestjs/jwt");
const prisma_service_1 = require("../../shared/prisma.service");
const user_interface_1 = require("../identity/domain/repositories/user.interface");
const prisma_user_repository_1 = require("../identity/infrastructure/repositories/prisma-user.repository");
const sync_identity_handler_1 = require("../identity/application/handlers/user/sync-identity.handler");
const role_interface_1 = require("../identity/domain/repositories/role.interface");
const prisma_role_repository_1 = require("../identity/infrastructure/repositories/prisma-role.repository");
const i_auth_config_1 = require("../identity/application/config/i-auth-config");
const env_auth_config_1 = require("../identity/application/config/env-auth-config");
const redis_pkce_store_1 = require("./pkce/redis-pkce.store");
const inmemory_refresh_store_1 = require("./refresh/inmemory-refresh.store");
const oidc_service_1 = require("./oidc.service");
const role_sync_service_1 = require("./role-sync.service");
const redis_service_1 = require("../../shared/redis.service");
const group_hash_service_1 = require("./group-hash.service");
const authentication_service_1 = require("./authentication.service");
const event_bus_service_1 = require("../../core/event-bus/event-bus.service");
const audit_service_1 = require("../audit/audit.service");
const authorization_module_1 = require("../authorization/authorization.module");
let AuthModule = class AuthModule {
};
exports.AuthModule = AuthModule;
exports.AuthModule = AuthModule = __decorate([
(0, common_1.Module)({
imports: [
config_1.ConfigModule,
authorization_module_1.AuthorizationModule,
jwt_1.JwtModule.registerAsync({
imports: [config_1.ConfigModule],
useFactory: async (config) => ({
secret: config.get('RAYLAB_JWT_SECRET') || 'raylab-secret',
signOptions: { algorithm: 'HS256' },
}),
inject: [config_1.ConfigService],
}),
],
controllers: [auth_controller_1.AuthController],
providers: [
auth_service_1.AuthService,
prisma_service_1.PrismaService,
prisma_user_repository_1.PrismaUserRepository,
prisma_role_repository_1.PrismaRoleRepository,
sync_identity_handler_1.SyncIdentityHandler,
{ provide: user_interface_1.IUser, useClass: prisma_user_repository_1.PrismaUserRepository },
{ provide: role_interface_1.IRole, useClass: prisma_role_repository_1.PrismaRoleRepository },
{ provide: i_auth_config_1.IAuthConfig, useClass: env_auth_config_1.EnvAuthConfig },
// In-memory PKCE and Refresh stores (Redis removed)
redis_pkce_store_1.RedisPkceStore,
inmemory_refresh_store_1.InMemoryRefreshStore,
// OIDC & Role Sync
oidc_service_1.OidcService,
role_sync_service_1.RoleSyncService,
group_hash_service_1.GroupHashService,
authentication_service_1.AuthenticationService,
event_bus_service_1.EventBus,
audit_service_1.AuditService,
redis_service_1.RedisService,
],
exports: [auth_service_1.AuthService, oidc_service_1.OidcService, role_sync_service_1.RoleSyncService, authentication_service_1.AuthenticationService, event_bus_service_1.EventBus],
})
], AuthModule);
//# sourceMappingURL=auth.module.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,uDAAmD;AACnD,iDAA6C;AAC7C,2CAA6D;AAC7D,qCAAwC;AACxC,gEAA4D;AAC5D,mFAAuE;AACvE,2GAAsG;AACtG,uGAAkG;AAClG,mFAAuE;AACvE,2GAAsG;AACtG,gFAA2E;AAC3E,oFAA+E;AAC/E,8DAAyD;AACzD,6EAAwE;AACxE,iDAA6C;AAC7C,2DAAsD;AACtD,8DAA0D;AAC1D,6DAAwD;AACxD,qEAAiE;AACjE,8EAAkE;AAClE,0DAAsD;AACtD,gFAA4E;AA0CrE,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAvCtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY;YACZ,0CAAmB;YACnB,eAAS,CAAC,aAAa,CAAC;gBACtB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,UAAU,EAAE,KAAK,EAAE,MAAqB,EAAE,EAAE,CAAC,CAAC;oBAC5C,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,eAAe;oBAC1D,WAAW,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;iBACpC,CAAC;gBACF,MAAM,EAAE,CAAC,sBAAa,CAAC;aACxB,CAAC;SACH;QACD,WAAW,EAAE,CAAC,gCAAc,CAAC;QAC7B,SAAS,EAAE;YACT,0BAAW;YACX,8BAAa;YACb,6CAAoB;YACpB,6CAAoB;YACpB,2CAAmB;YACnB,EAAE,OAAO,EAAE,sBAAK,EAAE,QAAQ,EAAE,6CAAoB,EAAE;YAClD,EAAE,OAAO,EAAE,sBAAK,EAAE,QAAQ,EAAE,6CAAoB,EAAE;YAClD,EAAE,OAAO,EAAE,2BAAW,EAAE,QAAQ,EAAE,+BAAa,EAAE;YAEjD,oDAAoD;YACpD,iCAAc;YACd,6CAAoB;YAEpB,mBAAmB;YACnB,0BAAW;YACX,mCAAe;YACf,qCAAgB;YAChB,8CAAqB;YACrB,4BAAQ;YACR,4BAAY;YACZ,4BAAY;SACb;QACD,OAAO,EAAE,CAAC,0BAAW,EAAE,0BAAW,EAAE,mCAAe,EAAE,8CAAqB,EAAE,4BAAQ,CAAC;KACtF,CAAC;GACW,UAAU,CAAG"}
+209
View File
@@ -0,0 +1,209 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const jwt_1 = require("@nestjs/jwt");
const sync_identity_handler_1 = require("../identity/application/handlers/user/sync-identity.handler");
const user_interface_1 = require("../identity/domain/repositories/user.interface");
const prisma_service_1 = require("../../shared/prisma.service");
const redis_pkce_store_1 = require("./pkce/redis-pkce.store");
const inmemory_refresh_store_1 = require("./refresh/inmemory-refresh.store");
const openidClient = require('openid-client');
let AuthService = class AuthService {
config;
jwtService;
prisma;
userRepository;
syncIdentityHandler;
pkceStore;
refreshStore;
constructor(config, jwtService, prisma, userRepository, syncIdentityHandler, pkceStore, refreshStore) {
this.config = config;
this.jwtService = jwtService;
this.prisma = prisma;
this.userRepository = userRepository;
this.syncIdentityHandler = syncIdentityHandler;
this.pkceStore = pkceStore;
this.refreshStore = refreshStore;
}
issuer = null;
client = null;
async getIssuer() {
if (this.issuer)
return this.issuer;
const issuerUrl = this.config.get('AUTHENTIK_ISSUER');
if (!issuerUrl)
throw new Error('AUTHENTIK_ISSUER not configured');
this.issuer = await openidClient.Issuer.discover(issuerUrl);
return this.issuer;
}
async getClient() {
if (this.client)
return this.client;
const issuer = await this.getIssuer();
const clientId = this.config.get('AUTHENTIK_CLIENT_ID');
const clientSecret = this.config.get('AUTHENTIK_CLIENT_SECRET');
if (!clientId)
throw new Error('AUTHENTIK_CLIENT_ID not configured');
this.client = new issuer.Client({ client_id: clientId, client_secret: clientSecret });
return this.client;
}
async createAuthorizationRedirect(returnTo) {
const client = await this.getClient();
const redirectUri = this.config.get('AUTH_CALLBACK_URL') || `${this.config.get('APP_URL') || ''}/auth/callback`;
const state = require('crypto').randomUUID();
const code_verifier = openidClient.generators.codeVerifier();
const code_challenge = await openidClient.generators.codeChallenge(code_verifier);
const nonce = openidClient.generators.nonce();
await this.pkceStore.save(state, { code_verifier, nonce, returnTo }, 300);
const url = client.authorizationUrl({
redirect_uri: redirectUri,
scope: this.config.get('AUTHENTIK_DEFAULT_SCOPE') || 'openid email profile',
response_type: 'code',
code_challenge,
code_challenge_method: 'S256',
state,
nonce,
});
return url;
}
async handleCallback(code, state) {
const client = await this.getClient();
const pkce = await this.pkceStore.get(state);
if (!pkce)
throw new common_1.UnauthorizedException('Invalid or expired state');
// remove one-time state
await this.pkceStore.remove(state);
const redirectUri = this.config.get('AUTH_CALLBACK_URL') || `${this.config.get('APP_URL') || ''}/auth/callback`;
// exchange code
const tokenSet = await client.callback(redirectUri, { code, state }, { code_verifier: pkce.code_verifier, nonce: pkce.nonce });
// verify id_token and get claims
const claims = tokenSet.claims();
// fetch userinfo if available
let userInfo = null;
try {
if (tokenSet.access_token && client.userinfo) {
userInfo = await client.userinfo(tokenSet.access_token);
}
}
catch (e) {
// ignore
}
const identity = {
sub: userInfo?.sub || claims.sub || null,
preferred_username: userInfo?.preferred_username || userInfo?.username || userInfo?.email || claims.preferred_username || claims.email,
email: userInfo?.email || claims.email,
raw: { tokenSet, userInfo, claims },
};
// Sync identity to local user (create if needed)
const domainUser = await this.syncIdentityHandler.execute(identity);
// ensure active/not deleted
if (!domainUser.isActive)
throw new common_1.UnauthorizedException('User is not active');
if (domainUser.deletedAt)
throw new common_1.UnauthorizedException('User is deleted');
// create internal JWT
const jwtPayload = {
sub: domainUser.id,
preferred_username: domainUser.username,
email: domainUser.email,
};
const expiresIn = Number(this.config.get('RAYLAB_JWT_EXPIRES_IN') || 3600);
const access = this.jwtService.sign(jwtPayload, { expiresIn });
// create internal refresh token
const refreshToken = require('crypto').randomUUID();
const refreshTtl = Number(this.config.get('RAYLAB_REFRESH_EXPIRES_IN') || 30 * 24 * 3600); // default 30 days
await this.refreshStore.set(refreshToken, { userId: domainUser.id }, refreshTtl);
return {
accessToken: access,
refreshToken,
expiresIn,
refreshTtl,
user: {
id: domainUser.id,
username: domainUser.username,
email: domainUser.email,
roles: domainUser.roles || [],
},
returnTo: pkce.returnTo,
};
}
async refresh(refreshToken) {
if (!refreshToken)
throw new common_1.UnauthorizedException('Missing refresh token');
const data = await this.refreshStore.get(refreshToken);
if (!data)
throw new common_1.UnauthorizedException('Invalid refresh token');
const userId = data.userId;
// load user
const domainUser = await this.userRepository.getById(userId);
if (!domainUser)
throw new common_1.UnauthorizedException('User not found');
if (!domainUser.isActive)
throw new common_1.UnauthorizedException('User is not active');
// rotate refresh token
await this.refreshStore.del(refreshToken);
const newRefresh = require('crypto').randomUUID();
const refreshTtl = Number(this.config.get('RAYLAB_REFRESH_EXPIRES_IN') || 30 * 24 * 3600);
await this.refreshStore.set(newRefresh, { userId }, refreshTtl);
const expiresIn = Number(this.config.get('RAYLAB_JWT_EXPIRES_IN') || 3600);
const access = this.jwtService.sign({ sub: domainUser.id, preferred_username: domainUser.username, email: domainUser.email }, { expiresIn });
return { accessToken: access, refreshToken: newRefresh, expiresIn, refreshTtl };
}
async logout(refreshToken) {
if (refreshToken) {
await this.refreshStore.del(refreshToken);
}
const issuer = await this.getIssuer();
const endSession = issuer.metadata.end_session_endpoint;
const postLogout = this.config.get('APP_URL') || '/';
if (endSession) {
// Redirect to identity provider logout
const url = new URL(endSession);
if (postLogout)
url.searchParams.set('post_logout_redirect_uri', postLogout);
return url.toString();
}
return postLogout;
}
async me(token) {
if (!token)
throw new common_1.UnauthorizedException('Missing token');
try {
const payload = this.jwtService.verify(token);
const user = await this.userRepository.getById(payload.sub);
if (!user)
throw new common_1.UnauthorizedException('User not found');
return { id: user.id, username: user.username, email: user.email, roles: user.roles || [] };
}
catch (e) {
throw new common_1.UnauthorizedException('Invalid token');
}
}
};
exports.AuthService = AuthService;
exports.AuthService = AuthService = __decorate([
(0, common_1.Injectable)(),
__param(3, (0, common_1.Inject)(user_interface_1.IUser)),
__metadata("design:paramtypes", [config_1.ConfigService,
jwt_1.JwtService,
prisma_service_1.PrismaService,
user_interface_1.IUser,
sync_identity_handler_1.SyncIdentityHandler,
redis_pkce_store_1.RedisPkceStore,
inmemory_refresh_store_1.InMemoryRefreshStore])
], AuthService);
//# sourceMappingURL=auth.service.js.map
File diff suppressed because one or more lines are too long
+70
View File
@@ -0,0 +1,70 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var AuthenticationService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthenticationService = void 0;
const common_1 = require("@nestjs/common");
const oidc_service_1 = require("./oidc.service");
const prisma_service_1 = require("../../shared/prisma.service");
const role_sync_service_1 = require("./role-sync.service");
const authorization_service_1 = require("../authorization/authorization.service");
const event_bus_service_1 = require("../../core/event-bus/event-bus.service");
let AuthenticationService = AuthenticationService_1 = class AuthenticationService {
oidc;
prisma;
roleSync;
authorization;
events;
logger = new common_1.Logger(AuthenticationService_1.name);
constructor(oidc, prisma, roleSync, authorization, events) {
this.oidc = oidc;
this.prisma = prisma;
this.roleSync = roleSync;
this.authorization = authorization;
this.events = events;
}
async authenticate(bearerToken) {
// Validate token (signature/iss/aud/exp)
const claims = await this.oidc.verifyToken(bearerToken);
const sub = claims.sub;
if (!sub)
throw new Error('Invalid token: missing sub');
// Resolve identity
const identity = { sub, email: claims.email, preferred_username: claims.preferred_username, raw: claims };
// Find or create user (materialize)
let user = await this.prisma.user.findUnique({ where: { authentikId: sub } });
if (!user) {
user = await this.prisma.user.create({ data: { authentikId: sub, username: identity.preferred_username || identity.email || sub, email: identity.email || null } });
}
// Synchronize roles
const groups = Array.isArray(claims.groups) ? claims.groups : [];
await this.roleSync.syncUserRolesFromAuthentik(user.id, groups);
// Load permissions
const permissions = await this.authorization.getUserPermissions(user.id);
// Build request context
const rolesRows = await this.prisma.userRole.findMany({ where: { userId: user.id } });
const roles = rolesRows.map((r) => r.roleId);
const ctx = { user, identity, roles, permissions };
// Publish domain event
this.events.publish({ id: require('crypto').randomUUID(), timestamp: new Date().toISOString(), type: 'UserAuthenticated', payload: { userId: user.id, identity } });
return ctx;
}
};
exports.AuthenticationService = AuthenticationService;
exports.AuthenticationService = AuthenticationService = AuthenticationService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [oidc_service_1.OidcService,
prisma_service_1.PrismaService,
role_sync_service_1.RoleSyncService,
authorization_service_1.AuthorizationService,
event_bus_service_1.EventBus])
], AuthenticationService);
//# sourceMappingURL=authentication.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"authentication.service.js","sourceRoot":"","sources":["../../../src/modules/auth/authentication.service.ts"],"names":[],"mappings":"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"}
+4
View File
@@ -0,0 +1,4 @@
"use strict";
// Login DTO removed. Password grant has been removed in favor of Authorization Code + PKCE flow.
// Formerly contained username/password properties.
//# sourceMappingURL=login.dto.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"login.dto.js","sourceRoot":"","sources":["../../../../src/modules/auth/dto/login.dto.ts"],"names":[],"mappings":";AAAA,iGAAiG;AACjG,mDAAmD"}
+56
View File
@@ -0,0 +1,56 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.GroupHashService = void 0;
const common_1 = require("@nestjs/common");
const crypto = __importStar(require("crypto"));
let GroupHashService = class GroupHashService {
compute(groups) {
const sorted = (groups || []).slice().sort();
const data = sorted.join(',');
return crypto.createHash('sha256').update(data, 'utf8').digest('hex');
}
};
exports.GroupHashService = GroupHashService;
exports.GroupHashService = GroupHashService = __decorate([
(0, common_1.Injectable)()
], GroupHashService);
//# sourceMappingURL=group-hash.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"group-hash.service.js","sourceRoot":"","sources":["../../../src/modules/auth/group-hash.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA4C;AAC5C,+CAAiC;AAG1B,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC3B,OAAO,CAAC,MAAgB;QACtB,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACxE,CAAC;CACF,CAAA;AANY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;GACA,gBAAgB,CAM5B"}
+48
View File
@@ -0,0 +1,48 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var OidcGuard_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OidcGuard = void 0;
const common_1 = require("@nestjs/common");
const oidc_service_1 = require("../oidc.service");
const authentication_service_1 = require("../authentication.service");
let OidcGuard = OidcGuard_1 = class OidcGuard {
oidc;
authn;
logger = new common_1.Logger(OidcGuard_1.name);
constructor(oidc, authn) {
this.oidc = oidc;
this.authn = authn;
}
async canActivate(context) {
const req = context.switchToHttp().getRequest();
const auth = req.headers['authorization'] || req.headers['Authorization'];
if (!auth || typeof auth !== 'string' || !auth.startsWith('Bearer '))
throw new common_1.UnauthorizedException('Missing bearer token');
const token = auth.substring(7).trim();
try {
const ctx = await this.authn.authenticate(token);
// attach context to request under a structured key
req.raylabContext = ctx;
return true;
}
catch (e) {
this.logger.debug('Authentication failed', e.message);
throw new common_1.UnauthorizedException('Invalid token or authentication failed');
}
}
};
exports.OidcGuard = OidcGuard;
exports.OidcGuard = OidcGuard = OidcGuard_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [oidc_service_1.OidcService, authentication_service_1.AuthenticationService])
], OidcGuard);
//# sourceMappingURL=oidc.guard.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"oidc.guard.js","sourceRoot":"","sources":["../../../../src/modules/auth/guards/oidc.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAkH;AAClH,kDAA8C;AAC9C,sEAAkE;AAG3D,IAAM,SAAS,iBAAf,MAAM,SAAS;IAES;IAAoC;IADhD,MAAM,GAAG,IAAI,eAAM,CAAC,WAAS,CAAC,IAAI,CAAC,CAAC;IACrD,YAA6B,IAAiB,EAAmB,KAA4B;QAAhE,SAAI,GAAJ,IAAI,CAAa;QAAmB,UAAK,GAAL,KAAK,CAAuB;IAAG,CAAC;IAEjG,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,MAAM,IAAI,8BAAqB,CAAC,sBAAsB,CAAC,CAAC;QAC9H,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEvC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YACjD,mDAAmD;YACnD,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAG,CAAS,CAAC,OAAO,CAAC,CAAC;YAC/D,MAAM,IAAI,8BAAqB,CAAC,wCAAwC,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;CACF,CAAA;AApBY,8BAAS;oBAAT,SAAS;IADrB,IAAA,mBAAU,GAAE;qCAGwB,0BAAW,EAA0B,8CAAqB;GAFlF,SAAS,CAoBrB"}
+89
View File
@@ -0,0 +1,89 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var OidcService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OidcService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
let OidcService = OidcService_1 = class OidcService {
config;
jwksUri = null;
issuer;
audience;
logger = new common_1.Logger(OidcService_1.name);
constructor(config) {
this.config = config;
this.issuer = this.config.get('AUTHENTIK_ISSUER') || '';
this.audience = this.config.get('AUTHENTIK_AUDIENCE') || undefined;
const jwksUri = this.config.get('AUTHENTIK_JWKS_URI');
if (jwksUri)
this.jwksUri = jwksUri;
else if (this.issuer)
this.jwksUri = `${this.issuer.replace(/\/+$/, '')}/.well-known/jwks.json`;
}
async verifyToken(token) {
if (!this.jwksUri)
throw new Error('JWKS not configured');
try {
// dynamic import to avoid ESM loading issues in test environment
const jose = await Promise.resolve().then(() => __importStar(require('jose')));
const jwks = jose.createRemoteJWKSet(new URL(this.jwksUri));
const { payload } = await jose.jwtVerify(token, jwks, {
issuer: this.issuer || undefined,
audience: this.audience,
});
return payload;
}
catch (e) {
this.logger.debug('Token verification failed', e.message);
throw e;
}
}
};
exports.OidcService = OidcService;
exports.OidcService = OidcService = OidcService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_1.ConfigService])
], OidcService);
//# sourceMappingURL=oidc.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"oidc.service.js","sourceRoot":"","sources":["../../../src/modules/auth/oidc.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,2CAA+C;AAGxC,IAAM,WAAW,mBAAjB,MAAM,WAAW;IAMO;IALrB,OAAO,GAAkB,IAAI,CAAC;IAC9B,MAAM,CAAS;IACf,QAAQ,CAAgC;IACxC,MAAM,GAAG,IAAI,eAAM,CAAC,aAAW,CAAC,IAAI,CAAC,CAAC;IAE9C,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAS,kBAAkB,CAAC,IAAI,EAAE,CAAC;QAChE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAS,oBAAoB,CAAC,IAAI,SAAS,CAAC;QAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAS,oBAAoB,CAAC,CAAC;QAC9D,IAAI,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;aAC/B,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,wBAAwB,CAAC;IAClG,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,iEAAiE;YACjE,MAAM,IAAI,GAAG,wDAAa,MAAM,GAAC,CAAC;YAClC,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAC5D,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;gBACpD,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,SAAS;gBAChC,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACjB,CAAC,CAAC;YAEV,OAAO,OAA8B,CAAC;QACxC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAG,CAAW,CAAC,OAAO,CAAC,CAAC;YACrE,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;CACF,CAAA;AAhCY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;qCAO0B,sBAAa;GANvC,WAAW,CAgCvB"}
+56
View File
@@ -0,0 +1,56 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RedisPkceStore = void 0;
const common_1 = require("@nestjs/common");
let RedisPkceStore = class RedisPkceStore {
// In-memory PKCE store replacing Redis-backed implementation
map = new Map();
cleanupInterval;
constructor() {
// periodic cleanup
this.cleanupInterval = setInterval(() => {
const now = Date.now();
for (const [k, v] of this.map.entries()) {
if (v.expiresAt <= now)
this.map.delete(k);
}
}, 60 * 1000);
}
key(state) { return state; }
async save(state, data, ttlSeconds = 300) {
const expiresAt = Date.now() + ttlSeconds * 1000;
this.map.set(this.key(state), { ...data, expiresAt });
}
async get(state) {
const v = this.map.get(this.key(state));
if (!v)
return null;
if (v.expiresAt <= Date.now()) {
this.map.delete(this.key(state));
return null;
}
return { code_verifier: v.code_verifier, nonce: v.nonce, returnTo: v.returnTo };
}
async remove(state) {
this.map.delete(this.key(state));
}
onModuleDestroy() {
if (this.cleanupInterval)
clearInterval(this.cleanupInterval);
}
};
exports.RedisPkceStore = RedisPkceStore;
exports.RedisPkceStore = RedisPkceStore = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [])
], RedisPkceStore);
//# sourceMappingURL=redis-pkce.store.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"redis-pkce.store.js","sourceRoot":"","sources":["../../../../src/modules/auth/pkce/redis-pkce.store.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA6D;AAKtD,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,6DAA6D;IACrD,GAAG,GAAG,IAAI,GAAG,EAAqB,CAAC;IACnC,eAAe,CAAkB;IAEzC;QACE,mBAAmB;QACnB,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;gBACxC,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG;oBAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAChB,CAAC;IAEO,GAAG,CAAC,KAAa,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC;IAE5C,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,IAAiE,EAAE,UAAU,GAAG,GAAG;QAC3G,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC;QACjD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa;QACrB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACpB,IAAI,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;QACjF,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACxB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,eAAe;QACb,IAAI,IAAI,CAAC,eAAe;YAAE,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAChE,CAAC;CACF,CAAA;AApCY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,mBAAU,GAAE;;GACA,cAAc,CAoC1B"}
+53
View File
@@ -0,0 +1,53 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InMemoryRefreshStore = void 0;
const common_1 = require("@nestjs/common");
let InMemoryRefreshStore = class InMemoryRefreshStore {
map = new Map();
cleanupInterval;
constructor() {
this.cleanupInterval = setInterval(() => {
const now = Date.now();
for (const [k, v] of this.map.entries()) {
if (v.expiresAt <= now)
this.map.delete(k);
}
}, 60 * 1000);
}
async set(token, data, ttlSeconds) {
const expiresAt = Date.now() + ttlSeconds * 1000;
this.map.set(token, { userId: data.userId, expiresAt });
}
async get(token) {
const v = this.map.get(token);
if (!v)
return null;
if (v.expiresAt <= Date.now()) {
this.map.delete(token);
return null;
}
return { userId: v.userId };
}
async del(token) {
this.map.delete(token);
}
onModuleDestroy() {
if (this.cleanupInterval)
clearInterval(this.cleanupInterval);
}
};
exports.InMemoryRefreshStore = InMemoryRefreshStore;
exports.InMemoryRefreshStore = InMemoryRefreshStore = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [])
], InMemoryRefreshStore);
//# sourceMappingURL=inmemory-refresh.store.js.map
@@ -0,0 +1 @@
{"version":3,"file":"inmemory-refresh.store.js","sourceRoot":"","sources":["../../../../src/modules/auth/refresh/inmemory-refresh.store.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA6D;AAKtD,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACvB,GAAG,GAAG,IAAI,GAAG,EAAwB,CAAC;IACtC,eAAe,CAAkB;IAEzC;QACE,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;gBACxC,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG;oBAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa,EAAE,IAAwB,EAAE,UAAkB;QACnE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC;QACjD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa;QACrB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACpB,IAAI,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;QACvE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa;QACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,eAAe;QACb,IAAI,IAAI,CAAC,eAAe;YAAE,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAChE,CAAC;CACF,CAAA;AAhCY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;;GACA,oBAAoB,CAgChC"}
+88
View File
@@ -0,0 +1,88 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var RoleSyncService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RoleSyncService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../../shared/prisma.service");
const event_bus_service_1 = require("../../core/event-bus/event-bus.service");
const group_hash_service_1 = require("./group-hash.service");
const authorization_service_1 = require("../authorization/authorization.service");
let RoleSyncService = RoleSyncService_1 = class RoleSyncService {
prisma;
groupHash;
permissionCache;
events;
logger = new common_1.Logger(RoleSyncService_1.name);
constructor(prisma, groupHash, permissionCache, events) {
this.prisma = prisma;
this.groupHash = groupHash;
this.permissionCache = permissionCache;
this.events = events;
}
computeGroupHash(groups) {
return this.groupHash.compute(groups || []);
}
async mapGroupsToRoleIds(groups) {
if (!groups || groups.length === 0)
return [];
const mappings = await this.prisma.authGroupRoleMapping.findMany({ where: { authGroup: { in: groups } } });
const roleIds = mappings.map((m) => m.roleId);
return Array.from(new Set(roleIds));
}
async syncUserRolesFromAuthentik(userId, groups) {
const groupHash = this.computeGroupHash(groups || []);
const user = await this.prisma.user.findUnique({ where: { id: userId } });
if (!user)
throw new Error('User not found');
if (user.lastGroupHash === groupHash) {
this.logger.debug('Group hash unchanged, skipping sync');
return { skipped: true };
}
const roleIds = await this.mapGroupsToRoleIds(groups || []);
const previousRoleRows = await this.prisma.userRole.findMany({ where: { userId, source: 'AUTHENTIK' }, select: { roleId: true } });
const previousRoles = previousRoleRows.map((r) => r.roleId);
await this.prisma.$transaction(async (tx) => {
await tx.userRole.deleteMany({ where: { userId: userId, source: 'AUTHENTIK' } });
if (roleIds.length > 0) {
const createData = roleIds.map((rid) => ({ userId, roleId: rid, source: 'AUTHENTIK' }));
await tx.userRole.createMany({ data: createData, skipDuplicates: true });
}
await tx.user.update({ where: { id: userId }, data: { lastGroupHash: groupHash } });
});
// Invalidate permission cache through abstraction
try {
await this.permissionCache.invalidate(userId);
}
catch (e) {
this.logger.error('Failed to invalidate permission cache', e);
}
// Publish event for audit and other subscribers
this.events.publish({
id: require('crypto').randomUUID(),
timestamp: new Date().toISOString(),
type: 'RolesSynchronized',
payload: { userId, groups, assignedRoleIds: roleIds, previousRoles },
});
return { skipped: false, assignedRoleIds: roleIds };
}
};
exports.RoleSyncService = RoleSyncService;
exports.RoleSyncService = RoleSyncService = RoleSyncService_1 = __decorate([
(0, common_1.Injectable)(),
__param(2, (0, common_1.Inject)(authorization_service_1.PERMISSION_CACHE)),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
group_hash_service_1.GroupHashService, Object, event_bus_service_1.EventBus])
], RoleSyncService);
//# sourceMappingURL=role-sync.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"role-sync.service.js","sourceRoot":"","sources":["../../../src/modules/auth/role-sync.service.ts"],"names":[],"mappings":"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"}