/* * This file is part of a proprietary work. * * Copyright (c) 2025 Fossorial, Inc. * All rights reserved. * * This file is licensed under the Fossorial Commercial License. * You may not use this file except in compliance with the License. * Unauthorized use, copying, modification, or distribution is strictly prohibited. * * This file is not licensed under the AGPLv3. */ import config from "./config"; import { certificates, db } from "@server/db"; import { and, eq, isNotNull, or, inArray, sql } from "drizzle-orm"; import { decryptData } from "@server/lib/encryption"; import * as fs from "fs"; import logger from "@server/logger"; import cache from "@server/lib/cache"; let encryptionKeyPath = ""; let encryptionKeyHex = ""; let encryptionKey: Buffer; function loadEncryptData() { if (encryptionKey) { return; // already loaded } encryptionKeyPath = config.getRawPrivateConfig().server.encryption_key_path; if (!fs.existsSync(encryptionKeyPath)) { throw new Error( "Encryption key file not found. Please generate one first." ); } encryptionKeyHex = fs.readFileSync(encryptionKeyPath, "utf8").trim(); encryptionKey = Buffer.from(encryptionKeyHex, "hex"); } // Define the return type for clarity and type safety export type CertificateResult = { id: number; domain: string; queriedDomain: string; // The domain that was originally requested (may differ for wildcards) wildcard: boolean | null; certFile: string | null; keyFile: string | null; expiresAt: number | null; updatedAt?: number | null; }; export async function getValidCertificatesForDomains( domains: Set, useCache: boolean = true ): Promise> { loadEncryptData(); // Ensure encryption key is loaded const finalResults: CertificateResult[] = []; const domainsToQuery = new Set(); // 1. Check cache first if enabled if (useCache) { for (const domain of domains) { const cacheKey = `cert:${domain}`; const cachedCert = cache.get(cacheKey); if (cachedCert) { finalResults.push(cachedCert); // Valid cache hit } else { domainsToQuery.add(domain); // Cache miss or expired } } } else { // If caching is disabled, add all domains to the query set domains.forEach((d) => domainsToQuery.add(d)); } // 2. If all domains were resolved from the cache, return early if (domainsToQuery.size === 0) { const decryptedResults = decryptFinalResults(finalResults); return decryptedResults; } // 3. Prepare domains for the database query const domainsToQueryArray = Array.from(domainsToQuery); const parentDomainsToQuery = new Set(); domainsToQueryArray.forEach((domain) => { const parts = domain.split("."); // A wildcard can only match a domain with at least two parts (e.g., example.com) if (parts.length > 1) { parentDomainsToQuery.add(parts.slice(1).join(".")); } }); const parentDomainsArray = Array.from(parentDomainsToQuery); // 4. Build and execute a single, efficient Drizzle query // This query fetches all potential exact and wildcard matches in one database round-trip. const potentialCerts = await db .select() .from(certificates) .where( and( eq(certificates.status, "valid"), isNotNull(certificates.certFile), isNotNull(certificates.keyFile), or( // Condition for exact matches on the requested domains inArray(certificates.domain, domainsToQueryArray), // Condition for wildcard matches on the parent domains parentDomainsArray.length > 0 ? and( inArray(certificates.domain, parentDomainsArray), eq(certificates.wildcard, true) ) : // If there are no possible parent domains, this condition is false sql`false` ) ) ); // 5. Process the database results, prioritizing exact matches over wildcards const exactMatches = new Map(); const wildcardMatches = new Map(); for (const cert of potentialCerts) { if (cert.wildcard) { wildcardMatches.set(cert.domain, cert); } else { exactMatches.set(cert.domain, cert); } } for (const domain of domainsToQuery) { let foundCert: (typeof potentialCerts)[0] | undefined = undefined; // Priority 1: Check for an exact match (non-wildcard) if (exactMatches.has(domain)) { foundCert = exactMatches.get(domain); } // Priority 2: Check for a wildcard certificate that matches the exact domain else { if (wildcardMatches.has(domain)) { foundCert = wildcardMatches.get(domain); } // Priority 3: Check for a wildcard match on the parent domain else { const parts = domain.split("."); if (parts.length > 1) { const parentDomain = parts.slice(1).join("."); if (wildcardMatches.has(parentDomain)) { foundCert = wildcardMatches.get(parentDomain); } } } } // If a certificate was found, format it, add to results, and cache it if (foundCert) { logger.debug( `Creating result cert for ${domain} using cert from ${foundCert.domain}` ); const resultCert: CertificateResult = { id: foundCert.certId, domain: foundCert.domain, // The actual domain of the cert record queriedDomain: domain, // The domain that was originally requested wildcard: foundCert.wildcard, certFile: foundCert.certFile, keyFile: foundCert.keyFile, expiresAt: foundCert.expiresAt, updatedAt: foundCert.updatedAt }; finalResults.push(resultCert); // Add to cache for future requests, using the *requested domain* as the key if (useCache) { const cacheKey = `cert:${domain}`; cache.set(cacheKey, resultCert, 180); } } } const decryptedResults = decryptFinalResults(finalResults); return decryptedResults; } function decryptFinalResults( finalResults: CertificateResult[] ): CertificateResult[] { const validCertsDecrypted = finalResults.map((cert) => { // Decrypt and save certificate file const decryptedCert = decryptData( cert.certFile!, // is not null from query encryptionKey ); // Decrypt and save key file const decryptedKey = decryptData(cert.keyFile!, encryptionKey); // Return only the certificate data without org information return { ...cert, certFile: decryptedCert, keyFile: decryptedKey }; }); return validCertsDecrypted; }