netget
Version:
Rette Adepto/ Recibido Directamente.
430 lines (404 loc) • 15.2 kB
text/typescript
import sqlite3 from 'sqlite3';
import { open, Database } from 'sqlite';
const { Database: SQLiteDatabase } = sqlite3;
import * as path from 'path';
import * as fs from 'fs';
import { handlePermission } from '../modules/utils/handlePermissions.ts';
import chalk from 'chalk';
import { initializeDirectories } from '../modules/utils/GETDirs.ts';
import { loadOrCreateXConfig } from '../modules/NetGetX/config/xConfig.ts';
// Ensure necessary directories exist before database operations
await initializeDirectories();
const xConfig = await loadOrCreateXConfig();
const sqliteDatabasePath: string = xConfig.sqliteDatabasePath;
interface DomainRecord {
domain: string;
subdomain?: string;
email?: string;
sslMode?: string;
sslCertificate?: string;
sslCertificateKey?: string;
target?: string;
type?: string;
projectPath?: string;
rootDomain?: string;
owner?: string;
nginxConfig?: string;
}
interface DomainConfigResult {
domain: string;
type: string;
port?: number;
sslCertificate?: string;
target: string;
}
/**
* Function to create the table in the database
*/
async function createTable(): Promise<void> {
try {
const db = await open({
filename: sqliteDatabasePath,
driver: SQLiteDatabase
});
await db.exec(`
CREATE TABLE IF NOT EXISTS domains (
domain TEXT PRIMARY KEY,
subdomain TEXT,
email TEXT,
sslMode TEXT,
sslCertificate TEXT,
sslCertificateKey TEXT,
target TEXT,
type TEXT,
projectPath TEXT,
rootDomain TEXT,
owner TEXT,
nginxConfig TEXT
)
`);
// Close the database to release file handles
await db.close();
} catch (error: any) {
console.error(chalk.red(`\nFailed to create table in database: ${error.message}`));
}
}
/**
* Function to initialize the database
*/
export async function initializeDatabase(): Promise<Database> {
await createTable();
return open({
filename: sqliteDatabasePath,
driver: SQLiteDatabase
});
}
const dbPromise = initializeDatabase();
/**
* Function to add a domain
*/
export async function registerDomain(
domain: string,
subdomain?: string,
email?: string,
sslMode?: string,
sslCertificate?: string,
sslCertificateKey?: string,
target?: string,
type?: string,
projectPath?: string,
owner?: string
): Promise<void> {
const db = await dbPromise;
try {
const existingDomain = await db.get('SELECT * FROM domains WHERE domain = ?', [domain]);
if (existingDomain) {
throw new Error(`The domain ${domain} already exists.`);
}
await db.run(
'INSERT INTO domains (domain, subdomain, email, sslMode, sslCertificate, sslCertificateKey, target, type, projectPath, owner) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
[domain, subdomain, email, sslMode, sslCertificate, sslCertificateKey, target, type, projectPath, owner]);
} catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
`register the domain ${domain} in the database`,
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has write permissions for the current user.`
);
}
console.error(`Error adding domain ${domain}:`, error);
throw error;
}
}
/**
* Function to get all domains
*/
export async function getDomains(): Promise<DomainRecord[]> {
try {
const db = await dbPromise;
return await db.all('SELECT * FROM domains');
} catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
'get the list of domains from the database',
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has read permissions for the current user.`
);
}
console.error('Error getting domains:', error);
throw error;
}
}
/**
* Function to get a domain by its name
*/
export async function getDomainByName(domain: string): Promise<DomainRecord | undefined> {
try {
const db = await dbPromise;
return await db.get('SELECT * FROM domains WHERE domain = ?', [domain]);
} catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
`get the domain ${domain} from the database`,
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has read permissions for the current user.`
);
}
console.error(`Error getting the domain ${domain}:`, error);
throw error;
}
}
/**
* Function to update a domain
*/
export async function updateDomain(
domain: string,
subdomain?: string,
email?: string,
sslMode?: string,
sslCertificate?: string,
sslCertificateKey?: string,
target?: string,
type?: string,
projectPath?: string,
owner?: string
): Promise<void> {
try {
const db = await dbPromise;
await db.run(
'UPDATE domains SET subdomain = ?, email = ?, sslMode = ?, sslCertificate = ?, sslCertificateKey = ?, target = ?, type = ?, projectPath = ?, owner = ? WHERE domain = ?',
[subdomain, email, sslMode, sslCertificate, sslCertificateKey, target, type, projectPath, owner, domain]
);
}
catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
`update the domain ${domain} in the database`,
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has write permissions for the current user.`
);
}
console.error(`Error updating the domain ${domain}:`, error);
throw error;
}
}
/**
* Function to update the target of a domain
*/
export async function updateDomainTarget(domain: string, target: string): Promise<void> {
try {
const db = await dbPromise;
await db.run('UPDATE domains SET target = ? WHERE domain = ?', [target, domain]);
} catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
`update the target of the domain ${domain} in the database`,
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has write permissions for the current user.`
);
}
console.error(`Error updating the target of the domain ${domain}:`, error);
throw error;
}
}
/**
* Function to update the type of a domain
*/
export async function updateDomainType(domain: string, type: string): Promise<void> {
try {
const db = await dbPromise;
await db.run('UPDATE domains SET type = ? WHERE domain = ?', [type, domain]);
} catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
`update the type of the domain ${domain} in the database`,
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has write permissions for the current user.`
);
}
console.error(`Error updating the type of the domain ${domain}:`, error);
throw error;
}
}
/**
* Function to delete a domain
*/
export async function deleteDomain(domain: string): Promise<void> {
try {
const db = await dbPromise;
await db.run('DELETE FROM domains WHERE domain = ?', [domain]);
} catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
`delete the domain ${domain} from the database`,
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has write permissions for the current user.`
);
}
console.error(`Error deleting the domain ${domain}:`, error);
throw error;
}
}
/**
* Function to store configuration in the database
*/
export async function storeConfigInDB(
domain: string,
subdomain?: string,
sslMode?: string,
sslCertificate?: string,
sslCertificateKey?: string,
target?: string,
type?: string,
projectPath?: string,
owner?: string
): Promise<void> {
const db = await dbPromise;
try {
const existingDomain = await db.get('SELECT * FROM domains WHERE domain = ?', [domain]);
const domainOwner = owner || domain.split('.').slice(-2).join('.');
if (existingDomain) {
await db.run('UPDATE domains SET subdomain = ?, sslMode = ?, sslCertificate = ?, sslCertificateKey = ?, target = ?, type = ?, projectPath = ?, owner = ? WHERE domain = ?', [subdomain, sslMode, sslCertificate, sslCertificateKey, target, type, projectPath, domainOwner, domain]);
} else {
await db.run('INSERT INTO domains (domain, subdomain, sslMode, sslCertificate, sslCertificateKey, target, type, projectPath, owner) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', [domain, subdomain, sslMode, sslCertificate, sslCertificateKey, target, type, projectPath, domainOwner]);
}
} catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
`store the configuration of the domain ${domain} in the database`,
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has write permissions for the current user.`
);
}
console.error(`Error storing config for domain ${domain}:`, error);
throw error;
}
}
/**
* Function to write existing Nginx configurations to the database
*/
export async function writeExistingNginxConfigs(): Promise<void> {
const db = await dbPromise;
try {
const configDir = '/etc/nginx/XBlocks-available/';
const files = fs.readdirSync(configDir);
for (const file of files) {
const domain = path.basename(file, '.conf');
const nginxConfig = fs.readFileSync(path.join(configDir, file), 'utf-8');
const existingDomain = await db.get('SELECT * FROM domains WHERE domain = ?', [domain]);
if (existingDomain) {
await db.run('UPDATE domains SET nginxConfig = ? WHERE domain = ?', [nginxConfig, domain]);
} else {
await db.run('INSERT INTO domains (domain, nginxConfig) VALUES (?, ?)', [domain, nginxConfig]);
}
}
} catch (error: any) {
if (
error.code === 'EACCES' ||
error.code === 'SQLITE_CANTOPEN' ||
error.message?.includes('permission') ||
error.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
'read or write nginx configurations in the database',
`chmod 755 ${sqliteDatabasePath} && chmod 755 /etc/nginx/XBlocks-available/`,
`Make sure the files in /etc/nginx/XBlocks-available/ and ${sqliteDatabasePath} have read/write permissions for the current user.`
);
}
console.error('Error writing existing nginx configs:', error);
throw error;
}
}
/**
* Function to get the configuration of a domain
*/
function getConfig(domain: string): Promise<DomainConfigResult | undefined> {
return new Promise((resolve, reject) => {
const db = new SQLiteDatabase(sqliteDatabasePath);
db.get('SELECT domain, type, port, sslCertificate, sslCertificateKey AS target FROM domains WHERE domain = ? OR domain = ?', [domain, '*.' + domain.split('.').slice(1).join('.')], (err: Error | null, row: DomainConfigResult) => {
if (err) {
reject(err);
} else {
resolve(row);
}
});
});
}
/**
* Updates the SSL certificate paths in the database for a domain.
*/
export async function updateSSLCertificatePaths(domain: string, certPath: string, keyPath: string): Promise<void> {
return new Promise(async (resolve, reject) => {
const db = new SQLiteDatabase(sqliteDatabasePath);
db.run(
`UPDATE domains SET
sslCertificate = ?,
sslCertificateKey = ?
WHERE domain = ?`,
[certPath, keyPath, domain],
async (err: Error | null) => {
db.close();
if (err) {
if (
err.message?.includes('permission') ||
(err as any).code === 'EACCES' ||
(err as any).code === 'SQLITE_CANTOPEN' ||
err.message?.includes('SQLITE_CANTOPEN')
) {
await handlePermission(
`update the SSL certificate paths for the domain ${domain}`,
`chmod 755 ${sqliteDatabasePath}`,
`Make sure the file ${sqliteDatabasePath} has write permissions for the current user.`
);
}
console.log('Error updating SSL certificate paths in database:', err.message);
reject(err);
} else {
resolve();
}
}
);
});
}
export default { getConfig };
export type { DomainRecord, DomainConfigResult };