import { Injectable, NestInterceptor, ExecutionContext, CallHandler, HttpException, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { Request, Response } from 'express'; import { resolve } from 'path'; import { from, Observable, of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { DNSCacheService } from 'src/modules/objects/dns/dns-cache.service'; import { ManagerService } from 'src/modules/objects/manager/manager.service'; import { CachedZone } from 'src/types/dns.interfaces'; @Injectable() export class DomainInterceptor implements NestInterceptor { constructor( private dns: DNSCacheService, private manage: ManagerService, private config: ConfigService, ) {} async getOrLoad(domain: string): Promise { if (!this.dns.has(domain)) { const exists = await this.manage.getZone(domain); if (!exists) throw new HttpException('No such zonefile', 404); return this.dns.load( domain, resolve( process.cwd(), this.config.get('zoneDir'), `${domain}.zone`, ), ); } const get = await this.dns.get(domain); if (!get) { throw new HttpException('Misconfigured domain zone file.', 400); } return get; } intercept(context: ExecutionContext, next: CallHandler): Observable { const request = context.switchToHttp().getRequest(); const response = context.switchToHttp().getResponse(); let base = of(null); const domain = request.params.domain; if (domain) { base = from( (async () => { const domainCache = await this.getOrLoad(domain); response.locals.domain = domain; response.locals.cached = domainCache; return null; })(), ); } return base.pipe(switchMap(() => next.handle())); } }