feat: Implement repositories for authentication, certificates, metrics, and platform services
- Added AuthRepository for user and settings management with CRUD operations. - Introduced CertificateRepository to handle domains, certificates, and requirements. - Created MetricsRepository for managing metrics and logs. - Developed PlatformRepository for platform services and resources management. - Established RegistryRepository for registry and token operations. - Implemented ServiceRepository for CRUD operations on services. - Defined types and interfaces in types.ts for database interactions.
This commit is contained in:
381
ts/database/repositories/certificate.repository.ts
Normal file
381
ts/database/repositories/certificate.repository.ts
Normal file
@@ -0,0 +1,381 @@
|
||||
/**
|
||||
* Certificate Repository
|
||||
* Handles CRUD operations for domains, certificates, cert_requirements, and legacy ssl_certificates
|
||||
*/
|
||||
|
||||
import { BaseRepository } from '../base.repository.ts';
|
||||
import type { TBindValue } from '../types.ts';
|
||||
import type { IDomain, ICertificate, ICertRequirement, ISslCertificate } from '../../types.ts';
|
||||
|
||||
export class CertificateRepository extends BaseRepository {
|
||||
// ============ Domains ============
|
||||
|
||||
createDomain(domain: Omit<IDomain, 'id'>): IDomain {
|
||||
this.query(
|
||||
`INSERT INTO domains (domain, dns_provider, cloudflare_zone_id, is_obsolete, default_wildcard, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
domain.domain,
|
||||
domain.dnsProvider,
|
||||
domain.cloudflareZoneId,
|
||||
domain.isObsolete ? 1 : 0,
|
||||
domain.defaultWildcard ? 1 : 0,
|
||||
domain.createdAt,
|
||||
domain.updatedAt,
|
||||
]
|
||||
);
|
||||
|
||||
return this.getDomainByName(domain.domain)!;
|
||||
}
|
||||
|
||||
getDomainByName(domain: string): IDomain | null {
|
||||
const rows = this.query('SELECT * FROM domains WHERE domain = ?', [domain]);
|
||||
return rows.length > 0 ? this.rowToDomain(rows[0]) : null;
|
||||
}
|
||||
|
||||
getDomainById(id: number): IDomain | null {
|
||||
const rows = this.query('SELECT * FROM domains WHERE id = ?', [id]);
|
||||
return rows.length > 0 ? this.rowToDomain(rows[0]) : null;
|
||||
}
|
||||
|
||||
getAllDomains(): IDomain[] {
|
||||
const rows = this.query('SELECT * FROM domains ORDER BY domain ASC');
|
||||
return rows.map((row) => this.rowToDomain(row));
|
||||
}
|
||||
|
||||
getDomainsByProvider(provider: 'cloudflare' | 'manual'): IDomain[] {
|
||||
const rows = this.query('SELECT * FROM domains WHERE dns_provider = ? ORDER BY domain ASC', [provider]);
|
||||
return rows.map((row) => this.rowToDomain(row));
|
||||
}
|
||||
|
||||
updateDomain(id: number, updates: Partial<IDomain>): void {
|
||||
const fields: string[] = [];
|
||||
const values: TBindValue[] = [];
|
||||
|
||||
if (updates.domain !== undefined) {
|
||||
fields.push('domain = ?');
|
||||
values.push(updates.domain);
|
||||
}
|
||||
if (updates.dnsProvider !== undefined) {
|
||||
fields.push('dns_provider = ?');
|
||||
values.push(updates.dnsProvider);
|
||||
}
|
||||
if (updates.cloudflareZoneId !== undefined) {
|
||||
fields.push('cloudflare_zone_id = ?');
|
||||
values.push(updates.cloudflareZoneId);
|
||||
}
|
||||
if (updates.isObsolete !== undefined) {
|
||||
fields.push('is_obsolete = ?');
|
||||
values.push(updates.isObsolete ? 1 : 0);
|
||||
}
|
||||
if (updates.defaultWildcard !== undefined) {
|
||||
fields.push('default_wildcard = ?');
|
||||
values.push(updates.defaultWildcard ? 1 : 0);
|
||||
}
|
||||
|
||||
fields.push('updated_at = ?');
|
||||
values.push(Date.now());
|
||||
values.push(id);
|
||||
|
||||
this.query(`UPDATE domains SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
|
||||
deleteDomain(id: number): void {
|
||||
this.query('DELETE FROM domains WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
private rowToDomain(row: any): IDomain {
|
||||
return {
|
||||
id: Number(row.id || row[0]),
|
||||
domain: String(row.domain || row[1]),
|
||||
dnsProvider: (row.dns_provider || row[2]) as IDomain['dnsProvider'],
|
||||
cloudflareZoneId: row.cloudflare_zone_id || row[3] || undefined,
|
||||
isObsolete: Boolean(row.is_obsolete || row[4]),
|
||||
defaultWildcard: Boolean(row.default_wildcard || row[5]),
|
||||
createdAt: Number(row.created_at || row[6]),
|
||||
updatedAt: Number(row.updated_at || row[7]),
|
||||
};
|
||||
}
|
||||
|
||||
// ============ Certificates ============
|
||||
|
||||
createCertificate(cert: Omit<ICertificate, 'id'>): ICertificate {
|
||||
this.query(
|
||||
`INSERT INTO certificates (domain_id, cert_domain, is_wildcard, cert_pem, key_pem, fullchain_pem, expiry_date, issuer, is_valid, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
cert.domainId,
|
||||
cert.certDomain,
|
||||
cert.isWildcard ? 1 : 0,
|
||||
cert.certPem,
|
||||
cert.keyPem,
|
||||
cert.fullchainPem,
|
||||
cert.expiryDate,
|
||||
cert.issuer,
|
||||
cert.isValid ? 1 : 0,
|
||||
cert.createdAt,
|
||||
cert.updatedAt,
|
||||
]
|
||||
);
|
||||
|
||||
const rows = this.query('SELECT * FROM certificates WHERE id = last_insert_rowid()');
|
||||
return this.rowToCertificate(rows[0]);
|
||||
}
|
||||
|
||||
getCertificateById(id: number): ICertificate | null {
|
||||
const rows = this.query('SELECT * FROM certificates WHERE id = ?', [id]);
|
||||
return rows.length > 0 ? this.rowToCertificate(rows[0]) : null;
|
||||
}
|
||||
|
||||
getCertificatesByDomain(domainId: number): ICertificate[] {
|
||||
const rows = this.query('SELECT * FROM certificates WHERE domain_id = ? ORDER BY expiry_date DESC', [domainId]);
|
||||
return rows.map((row) => this.rowToCertificate(row));
|
||||
}
|
||||
|
||||
getAllCertificates(): ICertificate[] {
|
||||
const rows = this.query('SELECT * FROM certificates ORDER BY expiry_date DESC');
|
||||
return rows.map((row) => this.rowToCertificate(row));
|
||||
}
|
||||
|
||||
updateCertificate(id: number, updates: Partial<ICertificate>): void {
|
||||
const fields: string[] = [];
|
||||
const values: TBindValue[] = [];
|
||||
|
||||
if (updates.certDomain !== undefined) {
|
||||
fields.push('cert_domain = ?');
|
||||
values.push(updates.certDomain);
|
||||
}
|
||||
if (updates.isWildcard !== undefined) {
|
||||
fields.push('is_wildcard = ?');
|
||||
values.push(updates.isWildcard ? 1 : 0);
|
||||
}
|
||||
if (updates.certPem !== undefined) {
|
||||
fields.push('cert_pem = ?');
|
||||
values.push(updates.certPem);
|
||||
}
|
||||
if (updates.keyPem !== undefined) {
|
||||
fields.push('key_pem = ?');
|
||||
values.push(updates.keyPem);
|
||||
}
|
||||
if (updates.fullchainPem !== undefined) {
|
||||
fields.push('fullchain_pem = ?');
|
||||
values.push(updates.fullchainPem);
|
||||
}
|
||||
if (updates.expiryDate !== undefined) {
|
||||
fields.push('expiry_date = ?');
|
||||
values.push(updates.expiryDate);
|
||||
}
|
||||
if (updates.issuer !== undefined) {
|
||||
fields.push('issuer = ?');
|
||||
values.push(updates.issuer);
|
||||
}
|
||||
if (updates.isValid !== undefined) {
|
||||
fields.push('is_valid = ?');
|
||||
values.push(updates.isValid ? 1 : 0);
|
||||
}
|
||||
|
||||
fields.push('updated_at = ?');
|
||||
values.push(Date.now());
|
||||
values.push(id);
|
||||
|
||||
this.query(`UPDATE certificates SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
|
||||
deleteCertificate(id: number): void {
|
||||
this.query('DELETE FROM certificates WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
private rowToCertificate(row: any): ICertificate {
|
||||
return {
|
||||
id: Number(row.id || row[0]),
|
||||
domainId: Number(row.domain_id || row[1]),
|
||||
certDomain: String(row.cert_domain || row[2]),
|
||||
isWildcard: Boolean(row.is_wildcard || row[3]),
|
||||
certPem: String(row.cert_pem || row[4] || ''),
|
||||
keyPem: String(row.key_pem || row[5] || ''),
|
||||
fullchainPem: String(row.fullchain_pem || row[6] || ''),
|
||||
expiryDate: Number(row.expiry_date || row[7]),
|
||||
issuer: String(row.issuer || row[8]),
|
||||
isValid: Boolean(row.is_valid || row[9]),
|
||||
createdAt: Number(row.created_at || row[10]),
|
||||
updatedAt: Number(row.updated_at || row[11]),
|
||||
};
|
||||
}
|
||||
|
||||
// ============ Certificate Requirements ============
|
||||
|
||||
createCertRequirement(req: Omit<ICertRequirement, 'id'>): ICertRequirement {
|
||||
this.query(
|
||||
`INSERT INTO cert_requirements (service_id, domain_id, subdomain, certificate_id, status, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
req.serviceId,
|
||||
req.domainId,
|
||||
req.subdomain,
|
||||
req.certificateId,
|
||||
req.status,
|
||||
req.createdAt,
|
||||
req.updatedAt,
|
||||
]
|
||||
);
|
||||
|
||||
const rows = this.query('SELECT * FROM cert_requirements WHERE id = last_insert_rowid()');
|
||||
return this.rowToCertRequirement(rows[0]);
|
||||
}
|
||||
|
||||
getCertRequirementById(id: number): ICertRequirement | null {
|
||||
const rows = this.query('SELECT * FROM cert_requirements WHERE id = ?', [id]);
|
||||
return rows.length > 0 ? this.rowToCertRequirement(rows[0]) : null;
|
||||
}
|
||||
|
||||
getCertRequirementsByService(serviceId: number): ICertRequirement[] {
|
||||
const rows = this.query('SELECT * FROM cert_requirements WHERE service_id = ?', [serviceId]);
|
||||
return rows.map((row) => this.rowToCertRequirement(row));
|
||||
}
|
||||
|
||||
getCertRequirementsByDomain(domainId: number): ICertRequirement[] {
|
||||
const rows = this.query('SELECT * FROM cert_requirements WHERE domain_id = ?', [domainId]);
|
||||
return rows.map((row) => this.rowToCertRequirement(row));
|
||||
}
|
||||
|
||||
getAllCertRequirements(): ICertRequirement[] {
|
||||
const rows = this.query('SELECT * FROM cert_requirements ORDER BY created_at DESC');
|
||||
return rows.map((row) => this.rowToCertRequirement(row));
|
||||
}
|
||||
|
||||
updateCertRequirement(id: number, updates: Partial<ICertRequirement>): void {
|
||||
const fields: string[] = [];
|
||||
const values: TBindValue[] = [];
|
||||
|
||||
if (updates.subdomain !== undefined) {
|
||||
fields.push('subdomain = ?');
|
||||
values.push(updates.subdomain);
|
||||
}
|
||||
if (updates.certificateId !== undefined) {
|
||||
fields.push('certificate_id = ?');
|
||||
values.push(updates.certificateId);
|
||||
}
|
||||
if (updates.status !== undefined) {
|
||||
fields.push('status = ?');
|
||||
values.push(updates.status);
|
||||
}
|
||||
|
||||
fields.push('updated_at = ?');
|
||||
values.push(Date.now());
|
||||
values.push(id);
|
||||
|
||||
this.query(`UPDATE cert_requirements SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
|
||||
deleteCertRequirement(id: number): void {
|
||||
this.query('DELETE FROM cert_requirements WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
private rowToCertRequirement(row: any): ICertRequirement {
|
||||
return {
|
||||
id: Number(row.id || row[0]),
|
||||
serviceId: Number(row.service_id || row[1]),
|
||||
domainId: Number(row.domain_id || row[2]),
|
||||
subdomain: String(row.subdomain || row[3]),
|
||||
certificateId: row.certificate_id || row[4] || undefined,
|
||||
status: String(row.status || row[5]) as ICertRequirement['status'],
|
||||
createdAt: Number(row.created_at || row[6]),
|
||||
updatedAt: Number(row.updated_at || row[7]),
|
||||
};
|
||||
}
|
||||
|
||||
// ============ SSL Certificates (Legacy API) ============
|
||||
|
||||
async createSSLCertificate(cert: Omit<ISslCertificate, 'id'>): Promise<ISslCertificate> {
|
||||
// First, ensure domain exists in domains table
|
||||
let domainRecord = this.getDomainByName(cert.domain);
|
||||
if (!domainRecord) {
|
||||
const now = Date.now();
|
||||
domainRecord = this.createDomain({
|
||||
domain: cert.domain,
|
||||
dnsProvider: null,
|
||||
isObsolete: false,
|
||||
defaultWildcard: true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
this.query(
|
||||
`INSERT INTO certificates (domain_id, cert_domain, is_wildcard, cert_pem, key_pem, fullchain_pem, expiry_date, issuer, is_valid, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
domainRecord.id,
|
||||
cert.domain,
|
||||
0,
|
||||
cert.certPem,
|
||||
cert.keyPem,
|
||||
cert.fullchainPem,
|
||||
cert.expiryDate,
|
||||
cert.issuer,
|
||||
1,
|
||||
now,
|
||||
now,
|
||||
]
|
||||
);
|
||||
|
||||
return this.getSSLCertificate(cert.domain)!;
|
||||
}
|
||||
|
||||
getSSLCertificate(domain: string): ISslCertificate | null {
|
||||
const rows = this.query('SELECT * FROM certificates WHERE cert_domain = ?', [domain]);
|
||||
return rows.length > 0 ? this.rowToSSLCert(rows[0]) : null;
|
||||
}
|
||||
|
||||
getAllSSLCertificates(): ISslCertificate[] {
|
||||
const rows = this.query('SELECT * FROM certificates ORDER BY expiry_date ASC');
|
||||
return rows.map((row) => this.rowToSSLCert(row));
|
||||
}
|
||||
|
||||
updateSSLCertificate(domain: string, updates: Partial<ISslCertificate>): void {
|
||||
const fields: string[] = [];
|
||||
const values: TBindValue[] = [];
|
||||
|
||||
if (updates.certPem) {
|
||||
fields.push('cert_pem = ?');
|
||||
values.push(updates.certPem);
|
||||
}
|
||||
if (updates.keyPem) {
|
||||
fields.push('key_pem = ?');
|
||||
values.push(updates.keyPem);
|
||||
}
|
||||
if (updates.fullchainPem) {
|
||||
fields.push('fullchain_pem = ?');
|
||||
values.push(updates.fullchainPem);
|
||||
}
|
||||
if (updates.expiryDate) {
|
||||
fields.push('expiry_date = ?');
|
||||
values.push(updates.expiryDate);
|
||||
}
|
||||
|
||||
fields.push('updated_at = ?');
|
||||
values.push(Date.now());
|
||||
values.push(domain);
|
||||
|
||||
this.query(`UPDATE certificates SET ${fields.join(', ')} WHERE cert_domain = ?`, values);
|
||||
}
|
||||
|
||||
deleteSSLCertificate(domain: string): void {
|
||||
this.query('DELETE FROM certificates WHERE cert_domain = ?', [domain]);
|
||||
}
|
||||
|
||||
private rowToSSLCert(row: any): ISslCertificate {
|
||||
return {
|
||||
id: Number(row.id || row[0]),
|
||||
domain: String(row.cert_domain || row[2] || ''),
|
||||
certPem: String(row.cert_pem || row[4] || ''),
|
||||
keyPem: String(row.key_pem || row[5] || ''),
|
||||
fullchainPem: String(row.fullchain_pem || row[6] || ''),
|
||||
expiryDate: Number(row.expiry_date || row[7]),
|
||||
issuer: String(row.issuer || row[8]),
|
||||
createdAt: Number(row.created_at || row[10]),
|
||||
updatedAt: Number(row.updated_at || row[11]),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user