Purpose: Health check endpoint to verify service availability
HTTP Method: GET
Authentication: None (Public endpoint)
Request Parameters: None
Response Format:
{
"status": "success",
"message": "Storage Layer of Zyotra is running",
"Timestamp": "2024-01-01T00:00:00.000Z"
}Database Operations: None
External Services: None
Purpose: Deploys PostgreSQL database on a remote VPS machine. Installs PostgreSQL if not present, creates database and user, configures remote access, and stores metadata.
HTTP Method: POST
Authentication: Protected by checkAuth middleware (JWT token required)
Request Parameters:
- Body:
{ vpsId: string; // VPS machine ID vpsIp: string; // VPS machine IP address dbName: string; // Database name to create userName: string; // PostgreSQL username password: string; // PostgreSQL password }
Response Format:
- Success (200):
{ "status": 200, "message": "Postgres deployment started successfully" } - Error (400): Invalid request body or database already exists
- Error (403): Unauthorized access to machine
- Error (500): Internal server error
Database Operations:
- Read: Queries
deployed_dbtable to check for existing database - Write: Inserts new record into
deployed_dbtable
External Services:
- SSH connection to remote VPS
- PostgreSQL installation and configuration commands
- External database query for VPS machine verification
Logic Flow:
- Validate request body parameters
- Verify machine ownership via
verifyMachine() - Check if database already exists on the machine
- Decrypt VPS password
- Establish SSH connection
- Install PostgreSQL (if not installed)
- Start PostgreSQL service
- Create database user and database
- Configure remote access
- Store deployment metadata in database
- Clean up SSH connection
Error Handling:
- If deployment fails, attempts to drop the created database
- Always closes SSH connection in
finallyblock - Returns appropriate HTTP status codes
Purpose: Deletes a PostgreSQL database from a remote VPS machine and removes its metadata.
HTTP Method: DELETE
Authentication: Protected by checkAuth middleware
Request Parameters:
- Path:
id(database ID from metadata table) - Body: Not used (but code expects body with dbName, vpsIp, vpsId - potential bug)
Response Format:
- Success (200):
{ "status": 200, "message": "Database deleted successfully" } - Error (400): Database ID missing
- Error (404): Database not found
- Error (403): Unauthorized access to machine
- Error (500): Internal server error
Database Operations:
- Read: Queries
deployed_dbtable by ID to get database details - Delete: Removes record from
deployed_dbtable
External Services:
- SSH connection to remote VPS
- PostgreSQL commands to terminate connections and drop database
Logic Flow:
- Extract database ID from path parameters
- Query database metadata by ID
- Verify machine ownership
- Decrypt VPS password
- Establish SSH connection
- Terminate all connections to the database
- Drop the database
- Delete metadata record
- Close SSH connection
Security Considerations:
- Verifies user owns the VPS before deletion
- Ensures all connections are terminated before dropping database
Purpose: Retrieves list of all databases deployed by the authenticated user.
HTTP Method: GET
Authentication: Protected by checkAuth middleware
Request Parameters: None (uses userId from JWT token)
Response Format:
- Success (200):
{ "status": 200, "data": [ { "id": 1, "dbName": "mydb", "username": "dbuser", "host": "192.168.1.1", "dbType": "postgres", "vpsId": 1, "userId": 1, "status": "running", "createdAt": "2024-01-01T00:00:00.000Z" } ] } - Error (500): Database query failed
Database Operations:
- Read: Selects all records from
deployed_dbwhereuserIdmatches authenticated user
External Services: None
Logic Flow:
- Extract
userIdfrom JWT token (via middleware) - Query
deployed_dbtable filtered byuserId - Return results
Purpose: Retrieves list of all tables in a specific database on a remote VPS.
HTTP Method: POST
Authentication: Protected by checkAuth middleware
Request Parameters:
- Body:
{ databaseName: string; // Name of the database vpsId: string; // VPS machine ID vpsIp: string; // VPS machine IP address username: string; // PostgreSQL username }
Response Format:
- Success (200):
{ "status": 200, "data": ["users", "products", "orders"], "message": "Tables list fetched successfully" } - Error (400): Invalid request body
- Error (403): Unauthorized access to machine
- Error (500): Internal server error
Database Operations: None (only queries remote PostgreSQL)
External Services:
- SSH connection to remote VPS
- PostgreSQL query to
information_schema.tables
Logic Flow:
- Validate request body
- Verify machine ownership
- Decrypt VPS password
- Establish SSH connection
- Execute PostgreSQL query to get table names
- Parse and filter table names
- Return cleaned list
- Close SSH connection
Purpose: Retrieves all data from a specific table in a remote database, returned as CSV-parsed JSON.
HTTP Method: POST
Authentication: Protected by checkAuth middleware
Request Parameters:
- Body:
{ databaseName: string; // Name of the database vpsId: string; // VPS machine ID vpsIp: string; // VPS machine IP address tableName: string; // Name of the table username: string; // PostgreSQL username }
Response Format:
- Success (200):
{ "status": "success", "data": [ {"id": 1, "name": "John", "email": "john@example.com"}, {"id": 2, "name": "Jane", "email": "jane@example.com"} ] } - Error (400): Invalid request body
- Error (404): Invalid machine details or unauthorized
- Error (500): Internal server error
Database Operations: None (only queries remote PostgreSQL)
External Services:
- SSH connection to remote VPS
- PostgreSQL query with CSV output
- PapaParse for CSV parsing
Logic Flow:
- Validate request body
- Verify machine ownership
- Decrypt VPS password
- Establish SSH connection
- Validate table name (alphanumeric + underscore only)
- Execute PostgreSQL query with CSV output
- Parse CSV response into JSON
- Return parsed data
- Close SSH connection
Security Considerations:
- Table name validation prevents SQL injection
- Uses parameterized queries through shell escaping
Purpose: Validates JWT access token and extracts user ID for protected routes.
Parameters:
headers: Request headers (not used, but available)cookie: Request cookies containingaccessTokenset: Elysia context setter for status codes
Return Value:
- On success:
{ userId: string } - On failure: Sets status code and returns error message
Logic Flow:
- Extract
accessTokenfrom cookies - If token missing, return 419 status with error message
- Verify token using
verifyAccessToken() - If invalid, return 419 status
- Extract
userIdfrom verified token payload - Return
userIdfor use in route handlers
Error Handling:
- Missing token → 419 (EXPIRED_TOKEN)
- Invalid token → 419 (EXPIRED_TOKEN)
- Missing userId → 419 (EXPIRED_TOKEN)
Dependencies:
verifyAccessToken()fromsrc/jwt/verifyTokens.tsStatusCodeenum fromsrc/types/types.ts
Purpose: Orchestrates PostgreSQL deployment on remote VPS machine.
Parameters:
body: Request body containing deployment configurationset: Elysia context setteruserId: Extracted from JWT token via middleware
Return Value:
- Success:
{ status: 200, message: string } - Error:
{ status: number, message: string }
Logic Flow:
- Extract and validate request parameters
- Verify machine ownership via
verifyMachine() - Check for existing database on same host/name
- Decrypt VPS password
- Create SSH client and connect
- Create PostgresSSHHelper instance
- Install PostgreSQL (if needed)
- Start PostgreSQL service
- Create user and database
- Configure remote access
- Insert metadata into database
- Return success response
- On error: attempt to drop database, close SSH
Error Handling:
- Validation errors → 400
- Authorization errors → 403
- Deployment errors → 500 with cleanup
Dependencies:
verifyMachine(),decryptPassword(),SSHClient,PostgresSSHHelper,db,deployed_db
Purpose: Deletes a PostgreSQL database from remote VPS and removes metadata.
Parameters:
params: Route parameters containingidbody: Request body (declared but not used - potential bug)set: Elysia context setteruserId: Extracted from JWT token
Return Value:
- Success:
{ status: 200, message: string } - Error:
{ status: number, message: string }
Logic Flow:
- Extract database ID from params
- Query database metadata by ID
- Verify database exists
- Verify machine ownership
- Decrypt VPS password
- Establish SSH connection
- Drop database via PostgresSSHHelper
- Delete metadata record
- Close SSH connection
Error Handling:
- Missing ID → 400
- Database not found → 404
- Authorization error → 403
- Execution error → 500
Dependencies:
verifyMachine(),decryptPassword(),SSHClient,PostgresSSHHelper,db,deployed_db
Purpose: Retrieves all databases for authenticated user.
Parameters:
set: Elysia context setteruserId: Extracted from JWT token
Return Value:
- Success:
{ status: 200, data: DeployedDb[] } - Error:
{ status: 500, message: any }
Logic Flow:
- Query
deployed_dbtable filtered byuserId - Return results with 200 status
- On error, return 500 status
Dependencies:
db,deployed_dbschema,eqfrom drizzle-orm
Purpose: Retrieves list of tables from remote database.
Parameters:
body: Request body with database and VPS detailsset: Elysia context setteruserId: Extracted from JWT token
Return Value:
- Success:
{ status: 200, data: string[], message: string } - Error:
{ status: number, message: string }
Logic Flow:
- Validate request body
- Verify machine ownership
- Decrypt VPS password
- Establish SSH connection
- Get tables list via PostgresSSHHelper
- Parse table names
- Return cleaned list
- Close SSH connection
Dependencies:
verifyMachine(),decryptVpsPassword(),SSHClient,PostgresSSHHelper,parseTableNames()
Purpose: Retrieves data from a specific table in remote database.
Parameters:
body: Request body with database, table, and VPS detailsset: Elysia context setteruserId: Extracted from JWT token
Return Value:
- Success:
{ status: "success", data: any[] } - Error:
{ message: any }
Logic Flow:
- Validate request body
- Verify machine ownership
- Decrypt VPS password
- Establish SSH connection
- Get table data via PostgresSSHHelper (includes validation)
- Return parsed CSV data
- Close SSH connection
Dependencies:
verifyMachine(),decryptVpsPassword(),SSHClient,PostgresSSHHelper
Purpose: Provides high-level PostgreSQL management operations via SSH.
Constructor:
ssh: SSHClient- SSH client instance for command execution
Purpose: Installs PostgreSQL and contrib packages on remote machine.
Parameters:
onLog?: (chunk: string) => void- Optional callback for real-time output
Return Value: Promise<void>
Logic Flow:
- Run
sudo apt updateto refresh package list - Run
sudo apt install -y postgresql postgresql-contribto install PostgreSQL
Commands Executed:
sudo apt update- Updates package repository indexsudo apt install -y postgresql postgresql-contrib- Installs PostgreSQL server and contrib modules
Error Handling: Throws error if any command fails (via runSequential)
Purpose: Checks if PostgreSQL service is running.
Parameters: None
Return Value: Promise<boolean> - true if active, false otherwise
Logic Flow:
- Execute
systemctl is-active postgresql - Check if output equals "active"
- Return boolean result
Commands Executed:
sudo systemctl is-active postgresql- Returns "active" if service is running, "inactive" otherwise
Purpose: Starts PostgreSQL service.
Parameters:
onLog?: (chunk: string) => void
Return Value: Promise<void>
Commands Executed:
sudo systemctl start postgresql- Starts PostgreSQL service
Purpose: Creates a PostgreSQL database (NOTE: Has bug - throws error if database doesn't exist).
Parameters:
database: string- Database nameonLog?: (chunk: string) => void
Return Value: Promise<void>
Logic Flow:
- Check if database exists using grep
- If doesn't exist (output "0"), create database
- If exists, throw error (BUG: logic is inverted)
Commands Executed:
sudo -u postgres psql -lqt | cut -d \| -f 1 | grep -qw ${database} && echo "1" || echo "0"- Checks database existencesudo -u postgres createdb ${database}- Creates database
Bug: Logic is inverted - should create if output is "0", but throws error instead.
Purpose: Creates PostgreSQL user and database, grants privileges.
Parameters:
config: PostgresConfig-{ database, username?, password }onLog?: (chunk: string) => void
Return Value: Promise<void>
Logic Flow:
- Check if user exists via
pg_rolesquery - If user doesn't exist, create user with password
- Check if database exists
- If database doesn't exist, create database with owner
- Grant all privileges on database to user
Commands Executed:
sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${username}'"- Checks user existencesudo -u postgres psql -c "CREATE USER ${username} WITH PASSWORD '${password}';"- Creates usersudo -u postgres psql -lqt | cut -d \| -f 1 | grep -qw ${database} && echo "1" || echo "0"- Checks database existencesudo -u postgres psql -c "CREATE DATABASE ${database} OWNER ${username};"- Creates databasesudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE ${database} TO ${username};"- Grants privileges
Security Considerations:
- Password is passed in command string (potential security risk)
- Uses
sudo -u postgresto run commands as postgres user
Purpose: Executes a single SQL command on remote database.
Parameters:
sql: string- SQL command to executedatabase: string- Database name (default: "postgres")onLog?: (chunk: string) => void
Return Value: Promise<CommandResult> - Command execution result
Logic Flow:
- Escape double quotes in SQL string
- Execute SQL via psql command
- Return result
Commands Executed:
sudo -u postgres psql -d ${database} -c "${escapedSQL}"- Executes SQL command
Security Considerations:
- Escapes double quotes but doesn't prevent all SQL injection
- Should use parameterized queries or file-based execution for user input
Purpose: Executes SQL from a file on remote machine.
Parameters:
sqlContent: string- SQL file contentdatabase: string- Database nameonLog?: (chunk: string) => void
Return Value: Promise<void>
Logic Flow:
- Create temporary file path with timestamp
- Write SQL content to temp file using heredoc
- Execute SQL file via psql
- Delete temporary file
Commands Executed:
cat > ${tmpFile} << 'EOSQL' ... EOSQL- Writes SQL to temp filesudo -u postgres psql -d ${database} -f ${tmpFile}- Executes SQL filerm ${tmpFile}- Deletes temp file
Security Considerations:
- Uses heredoc with single quotes to prevent variable expansion
- Cleans up temp file after execution
Purpose: Configures PostgreSQL to accept remote connections.
Parameters:
onLog?: (chunk: string) => void
Return Value: Promise<void>
Logic Flow:
- Find PostgreSQL version directory
- Backup original configuration files
- Update
postgresql.confto listen on all addresses - Add remote access rule to
pg_hba.conf - Restart PostgreSQL service
Commands Executed:
ls /etc/postgresql/ | head -n 1- Gets PostgreSQL versionsudo cp /etc/postgresql/${version}/main/postgresql.conf ...bak- Backs up configsudo cp /etc/postgresql/${version}/main/pg_hba.conf ...bak- Backs up pg_hbasudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/" ...- Enables remote listeningecho "host all all 0.0.0.0/0 scram-sha-256" | sudo tee -a ...- Adds remote access rulesudo systemctl restart postgresql- Restarts service
Security Considerations:
- Opens PostgreSQL to all IPs (0.0.0.0/0) - security risk
- Uses scram-sha-256 authentication (secure)
- Backs up original configs before modification
Purpose: Drops a PostgreSQL database, terminating all connections first.
Parameters:
databaseName: string- Database to droponLog?: (chunk: string) => void
Return Value: Promise<void>
Logic Flow:
- Terminate all active connections to database
- Drop database
Commands Executed:
sudo -u postgres psql -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${databaseName}' AND pid <> pg_backend_pid();"- Terminates connectionssudo -u postgres psql -c "DROP DATABASE IF EXISTS ${databaseName};"- Drops database
Security Considerations:
- Excludes current connection from termination
- Uses
IF EXISTSto prevent errors if database doesn't exist
Purpose: Retrieves list of table names from a database.
Parameters:
databaseName: string- Database nameonLog?: (chunk: string) => void
Return Value: Promise<string[]> - Array of table names
Logic Flow:
- Query
information_schema.tablesfor public schema tables - Split output by newlines
- Trim each line
- Return array
Commands Executed:
sudo -u postgres psql -d ${databaseName} -c "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"- Gets table names
Note: Returns raw output including headers and formatting - should be parsed by parseTableNames()
Purpose: Retrieves all data from a table as CSV, parsed to JSON.
Parameters:
databaseName: string- Database nametableName: string- Table nameusername: string- PostgreSQL usernameonLog?: (chunk: string) => void
Return Value: Promise<any[]> - Parsed CSV data as JSON array
Logic Flow:
- Validate table name (alphanumeric + underscore only)
- Execute SELECT query with CSV output
- Check exit code
- Parse CSV with PapaParse
- Return parsed data
Commands Executed:
psql -U ${username} -d ${databaseName} -c "SELECT * FROM \"${tableName}\";" --csv- Gets table data as CSV
Security Considerations:
- Validates table name with regex:
/^[a-zA-Z_][a-zA-Z0-9_]*$/ - Escapes table name in double quotes
- Uses CSV output for safe parsing
Error Handling:
- Invalid table name → throws Error
- Query failure → throws Error with output
Dependencies:
- PapaParse for CSV parsing
Purpose: Verifies that a VPS machine belongs to the authenticated user and IP matches.
Parameters:
machineId: string- VPS machine IDuserId: string- Authenticated user IDmachineIp: string- Expected VPS IP address
Return Value:
{
status: boolean;
machine: any | null;
}Logic Flow:
- Query
vps_machinestable for machine with matching ID and ownerId - If not found, return
{ status: false, machine: null } - If found, verify IP address matches
- Return status and machine object
Database Operations:
- Queries external
DEPLOYMENT_MANAGER_DATABASE_URLdatabase - Table:
vps_machines - Columns:
id,ownerId,vps_ip
Security Considerations:
- Uses parameterized query to prevent SQL injection
- Verifies both ownership and IP address
Dependencies:
poolfromsrc/db/pool.ts
Purpose: Decrypts AES-encrypted VPS password.
Parameters:
encryptedPassword: string- AES-encrypted password string
Return Value: Promise<string> - Decrypted password
Logic Flow:
- Decrypt using CryptoJS.AES.decrypt with ENCRYPTION_KEY
- Convert WordArray to UTF-8 string
- Return decrypted password
Security Considerations:
- Uses AES encryption
- Encryption key from environment variable
- Returns plaintext password (handle with care)
Dependencies:
- CryptoJS library
process.env.ENCRYPTION_KEY
Purpose: Cleans PostgreSQL psql output to extract only table names.
Parameters:
response: string[]- Raw output lines from psql
Return Value: string[] - Cleaned array of table names
Logic Flow:
- Trim each line
- Filter out:
- Header line ("table_name")
- Separator lines (all dashes)
- Footer lines (e.g., "(2 rows)")
- Empty strings
- Return filtered array
Regex Patterns:
- Separator:
/^-+$/- Matches lines with only dashes - Footer:
/^\(\d+\s+rows?\)$/i- Matches "(N rows)" pattern
Purpose: Verifies JWT access token and extracts user ID.
Parameters:
token: string- JWT token string
Return Value: Promise<{ userId: string } | false>
Logic Flow:
- Verify token using jsonwebtoken with ACCESS_TOKEN_SECRET
- Extract userId from payload
- Return userId or false on error
Error Handling:
- Invalid token → returns false
- Expired token → returns false
- Missing secret → throws error
Dependencies:
- jsonwebtoken library
process.env.ACCESS_TOKEN_SECRET
Purpose: Wrapper around ssh2 library for executing commands on remote machines.
Constructor:
config: ConnectConfig- SSH connection configuration (host, username, password, etc.)
Purpose: Establishes SSH connection to remote machine.
Return Value: Promise<void>
Logic Flow:
- Listen for 'ready' event → resolve
- Listen for 'error' event → reject
- Connect with provided config
Error Handling: Rejects promise on connection error
Purpose: Executes a shell command on remote machine.
Parameters:
command: string- Shell command to executeonLog?: (chunk: string) => void- Optional callback for real-time output
Return Value: Promise<CommandResult> - { command, output, exitCode }
Logic Flow:
- Execute command via SSH
- Collect stdout chunks
- Collect stderr chunks
- Call onLog callback for each chunk
- On stream close, resolve with result
Error Handling:
- Connection error → rejects promise
- Command execution error → rejects promise
Note: Includes artificial delays (Bun.sleep(1)) for output streaming
Purpose: Executes multiple commands sequentially, stopping on first failure.
Parameters:
commands: string[]- Array of commands to executeonLog?: (chunk: string) => void- Optional callback
Return Value: Promise<CommandResult[]> - Array of results
Logic Flow:
- Execute each command sequentially
- If any command fails (exitCode !== 0), throw error
- Return array of results
Error Handling:
- Stops execution on first failure
- Throws error with command and exit code
Purpose: Closes SSH connection.
Return Value: void
Logic Flow: Calls conn.end() to close connection
- Purpose: Refreshes package repository index
- Why: Ensures latest package versions are available
- Flags: None
- Expected Output: Package list update messages
- Failure Scenarios: Network issues, repository errors
- Purpose: Installs PostgreSQL server and contrib modules
- Why: Required for PostgreSQL functionality
- Flags:
-y: Automatically answers "yes" to prompts
- Packages:
postgresql: Core PostgreSQL serverpostgresql-contrib: Additional modules and utilities
- Expected Output: Installation progress and completion messages
- Failure Scenarios: Insufficient disk space, dependency conflicts
- Purpose: Checks if PostgreSQL service is running
- Why: Verify service status before operations
- Flags: None
- Expected Output: "active" or "inactive"
- Failure Scenarios: Service not installed
- Purpose: Starts PostgreSQL service
- Why: Required for database operations
- Flags: None
- Expected Output: Service start confirmation
- Failure Scenarios: Service already running, configuration errors
- Purpose: Restarts PostgreSQL service
- Why: Required after configuration changes
- Flags: None
- Expected Output: Service restart confirmation
- Failure Scenarios: Configuration syntax errors
- Purpose: Checks if PostgreSQL user exists
- Why: Avoid creating duplicate users
- Flags:
-u postgres: Run as postgres user-t: Print rows only (no headers)-A: Unaligned output mode-c: Execute command
- Expected Output: "1" if user exists, empty if not
- Failure Scenarios: PostgreSQL not running, permission errors
- Purpose: Creates PostgreSQL user with password
- Why: Required for database access
- Flags:
-u postgres: Run as postgres user-c: Execute SQL command
- Security Risk: Password in command string (visible in process list)
- Expected Output: CREATE ROLE confirmation
- Failure Scenarios: User already exists, invalid password format
- Purpose: Checks if database exists
- Why: Avoid creating duplicate databases
- Command Breakdown:
psql -lqt: List databases, tabular format, tuples onlycut -d \| -f 1: Extract first column (database name)grep -qw ${database}: Quiet word match for database name&& echo "1" || echo "0": Return 1 if found, 0 if not
- Expected Output: "1" or "0"
- Failure Scenarios: PostgreSQL not running
- Purpose: Creates PostgreSQL database
- Why: Required for storing data
- Flags: None
- Expected Output: Database creation confirmation
- Failure Scenarios: Database already exists, permission errors
- Purpose: Creates database with specific owner
- Why: Assigns ownership to created user
- Flags:
-u postgres: Run as postgres user-c: Execute SQL command
- Expected Output: CREATE DATABASE confirmation
- Failure Scenarios: Database exists, user doesn't exist
- Purpose: Grants all privileges on database to user
- Why: Allows user to manage database
- Flags:
-u postgres: Run as postgres user-c: Execute SQL command
- Expected Output: GRANT confirmation
- Failure Scenarios: Database or user doesn't exist
sudo -u postgres psql -d ${database} -c "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"
- Purpose: Lists all tables in public schema
- Why: Get table names for UI display
- Flags:
-u postgres: Run as postgres user-d ${database}: Connect to specific database-c: Execute SQL command
- Expected Output: Table names with headers and formatting
- Failure Scenarios: Database doesn't exist, permission errors
- Purpose: Retrieves all rows from table as CSV
- Why: Easy parsing and data transfer
- Flags:
-U ${username}: Connect as specific user-d ${database}: Connect to database-c: Execute SQL command--csv: Output in CSV format
- Security: Table name validated and escaped
- Expected Output: CSV data with headers
- Failure Scenarios: Table doesn't exist, permission errors, invalid table name
sudo -u postgres psql -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${databaseName}' AND pid <> pg_backend_pid();"
- Purpose: Terminates all connections to database
- Why: Required before dropping database (PostgreSQL doesn't allow dropping database with active connections)
- Flags:
-u postgres: Run as postgres user-c: Execute SQL command
- SQL Breakdown:
pg_stat_activity: System view showing active connectionspg_terminate_backend(): Function to terminate connectionpid <> pg_backend_pid(): Excludes current connection
- Expected Output: Termination confirmations
- Failure Scenarios: No active connections, permission errors
- Purpose: Drops database
- Why: Removes database from system
- Flags:
-u postgres: Run as postgres user-c: Execute SQL command
- SQL:
IF EXISTSprevents errors if database doesn't exist - Expected Output: DROP DATABASE confirmation
- Failure Scenarios: Active connections (should be terminated first), permission errors
- Purpose: Gets PostgreSQL version directory name
- Why: Configuration files are version-specific
- Command Breakdown:
ls /etc/postgresql/: Lists version directorieshead -n 1: Gets first line (version)
- Expected Output: Version number (e.g., "14", "15")
- Failure Scenarios: PostgreSQL not installed, permission errors
- Purpose: Backs up PostgreSQL configuration file
- Why: Allows rollback if configuration fails
- Flags: None
- Expected Output: File copy confirmation
- Failure Scenarios: File doesn't exist, permission errors
- Purpose: Enables PostgreSQL to listen on all network interfaces
- Why: Required for remote connections
- Command Breakdown:
sed -i: In-place file editings/.../.../: Substitute pattern#listen_addresses = 'localhost': Commented defaultlisten_addresses = '*': Listen on all interfaces
- Expected Output: File modification confirmation
- Failure Scenarios: Pattern not found, permission errors
- Purpose: Adds remote access rule to pg_hba.conf
- Why: Allows remote connections with password authentication
- Command Breakdown:
echo: Outputs rule stringsudo tee -a: Appends to file with sudohost all all 0.0.0.0/0 scram-sha-256: Access rulehost: TCP/IP connectionall all: All databases, all users0.0.0.0/0: All IP addressesscram-sha-256: Authentication method
- Security Risk: Opens to all IPs (should be restricted)
- Expected Output: Rule appended to file
- Failure Scenarios: Permission errors, invalid syntax
- Purpose: Writes SQL content to temporary file
- Why: Required for executing SQL files via psql
- Command Breakdown:
cat > ${tmpFile}: Write to file<< 'EOSQL': Heredoc delimiter (single quotes prevent expansion)...: SQL contentEOSQL: End delimiter
- Expected Output: File created with SQL content
- Failure Scenarios: Disk full, permission errors
- Purpose: Executes SQL file
- Why: Allows executing multiple SQL statements
- Flags:
-u postgres: Run as postgres user-d ${database}: Connect to database-f: Execute file
- Expected Output: SQL execution results
- Failure Scenarios: SQL syntax errors, file doesn't exist
- Purpose: Deletes temporary file
- Why: Cleanup after SQL execution
- Flags: None
- Expected Output: File deletion confirmation
- Failure Scenarios: File doesn't exist, permission errors
- Implementation:
checkAuthmiddleware validates JWT tokens from cookies - Token Source:
cookie.accessToken - Verification: Uses
verifyAccessToken()withACCESS_TOKEN_SECRET - User Extraction: Extracts
userIdfrom token payload - Failure Handling: Returns 419 status code on invalid/missing token
Security Considerations:
- ✅ Uses secure JWT verification
⚠️ Token stored in cookies (should use httpOnly flag)⚠️ No token refresh mechanism⚠️ No rate limiting on authentication
- Implementation:
verifyMachine()function - Checks:
- Machine ID exists in database
- Machine belongs to authenticated user (
ownerIdmatches) - Provided IP matches stored IP (
vps_ip)
- Database: External
DEPLOYMENT_MANAGER_DATABASE_URL - Query: Parameterized to prevent SQL injection
Security Considerations:
- ✅ Prevents unauthorized access to other users' machines
- ✅ IP verification prevents IP spoofing
- ✅ Uses parameterized queries
- Implementation: Manual checks in controllers
- Pattern: Checks for required fields, returns 400 if missing
- Examples:
deployPostgresController: ValidatesvpsId,vpsIp,dbName,userName,passwordgetTablesListController: ValidatesdatabaseName,vpsId,vpsIp,usernamegetTableData: Validates all required fields
Security Considerations:
- ✅ Basic validation present
⚠️ No type validation (relies on TypeScript types)⚠️ No length limits on inputs⚠️ No special character validation (except table names)
- Implementation: Regex validation in
getTableData() - Pattern:
/^[a-zA-Z_][a-zA-Z0-9_]*$/ - Rules:
- Must start with letter or underscore
- Can contain letters, numbers, underscores
- Prevents SQL injection through table names
Security Considerations:
- ✅ Prevents SQL injection via table names
- ✅ Escapes table name in double quotes
- ✅ Validates before database query
- Drizzle ORM: Uses parameterized queries for metadata database
- Example:
db.select().from(deployed_db).where(eq(deployed_db.userId, userId)) - External Database: Uses
pool.query()with parameterized queries - Example:
pool.query('SELECT * FROM vps_machines WHERE id=$1', [machineId])
Security Considerations:
- ✅ Metadata queries use parameterized queries
⚠️ Shell commands use string interpolation (potential risk)⚠️ PostgreSQL commands executed via shell (not parameterized)
- Implementation: Escapes double quotes in SQL strings
- Example:
sql.replace(/"/g, '\\"')inexecuteSQL() - Limitation: Only escapes quotes, doesn't prevent all injection
Security Considerations:
⚠️ Limited escaping (only quotes)⚠️ User input in shell commands (database names, usernames)- ✅ Table names validated before use
⚠️ Database names and usernames not validated
Recommendations:
- Validate database names and usernames with regex
- Use PostgreSQL's
quote_ident()function - Consider using connection libraries instead of shell commands
- Storage: VPS passwords encrypted with AES
- Implementation:
decryptVpsPassword()uses CryptoJS.AES.decrypt - Key:
ENCRYPTION_KEYfrom environment variables - Decryption: Happens before SSH connection
Security Considerations:
- ✅ Passwords encrypted at rest
- ✅ Encryption key in environment variable
⚠️ Decrypted passwords in memory (unavoidable)⚠️ No key rotation mechanism
- Storage: PostgreSQL passwords stored in plaintext in metadata database
- Transmission: Passwords sent in request body (should use HTTPS)
- Command Execution: Passwords visible in shell command strings
Security Considerations:
⚠️ Passwords stored in plaintext⚠️ Passwords visible in process list when creating users⚠️ Should use environment variables or password files- ✅ HTTPS should be used for transmission
Recommendations:
- Encrypt PostgreSQL passwords in metadata database
- Use
psqlwith password file (~/.pgpass) - Use environment variables for password passing
- Allowed Origins:
http://localhost:5173(development)https://zyotraportal.ramkrishna.cloud(production)
- Allowed Methods: GET, POST, PUT, DELETE
- Allowed Headers: Content-Type, Authorization
Security Considerations:
- ✅ CORS restricted to specific origins
- ✅ Methods limited to necessary ones
⚠️ Should validate Origin header server-side
- Configuration: Opens PostgreSQL to all IPs (
0.0.0.0/0) - Authentication: Uses
scram-sha-256(secure) - Risk: High - any IP can attempt connection
Security Considerations:
⚠️ CRITICAL: Opens database to entire internet- ✅ Uses secure authentication method
⚠️ Should restrict to specific IP ranges⚠️ Should use firewall rules
Recommendations:
- Restrict
pg_hba.confto specific IP ranges - Use firewall (iptables/ufw) to limit access
- Consider VPN or SSH tunneling for access
- Implementation: Returns error messages to client
- Examples: Database errors, SSH errors, validation errors
- Risk: May expose internal system information
Security Considerations:
⚠️ Error messages may expose system details⚠️ Stack traces not filtered- ✅ HTTP status codes used appropriately
Recommendations:
- Sanitize error messages before returning
- Log detailed errors server-side
- Return generic messages to clients
Current Status: ❌ No rate limiting implemented
Security Considerations:
⚠️ Vulnerable to brute force attacks⚠️ No protection against DDoS⚠️ No request throttling
Recommendations:
- Implement rate limiting middleware
- Limit authentication attempts
- Limit database operations per user
Client Request (POST /deploy-postgres)
↓
[checkAuth Middleware]
├─ Extract JWT token from cookie
├─ Verify token with ACCESS_TOKEN_SECRET
└─ Extract userId → Pass to controller
↓
[deployPostgresController]
├─ Validate request body
├─ Call verifyMachine(vpsId, userId, vpsIp)
│ └─ Query DEPLOYMENT_MANAGER_DB → vps_machines table
│ ├─ Check ownership (ownerId = userId)
│ └─ Verify IP match
├─ Check existing database in STORAGE_LAYER_DB
├─ Call decryptPassword(machine.vps_password)
│ └─ CryptoJS.AES.decrypt → Plaintext password
├─ Create SSHClient → Connect to VPS
├─ Create PostgresSSHHelper(ssh)
├─ pgHelper.install()
│ └─ SSH: sudo apt update && sudo apt install postgresql
├─ pgHelper.start()
│ └─ SSH: sudo systemctl start postgresql
├─ pgHelper.createUserAndDatabase()
│ ├─ SSH: Check user exists
│ ├─ SSH: CREATE USER (if needed)
│ ├─ SSH: Check database exists
│ ├─ SSH: CREATE DATABASE (if needed)
│ └─ SSH: GRANT PRIVILEGES
├─ pgHelper.allowRemoteConnections()
│ ├─ SSH: Backup configs
│ ├─ SSH: Update postgresql.conf
│ ├─ SSH: Update pg_hba.conf
│ └─ SSH: Restart PostgreSQL
├─ Insert metadata into STORAGE_LAYER_DB
│ └─ deployed_db table
└─ Return success response
Client Request (POST /get-tables-list)
↓
[checkAuth Middleware]
└─ Verify JWT → Extract userId
↓
[getTablesListController]
├─ Validate request body
├─ Call verifyMachine(vpsId, userId, vpsIp)
│ └─ Query DEPLOYMENT_MANAGER_DB
├─ Call decryptVpsPassword(machine.vps_password)
├─ Create SSHClient → Connect to VPS
├─ Create PostgresSSHHelper(ssh)
├─ pgHelper.getTablesList(databaseName)
│ └─ SSH: psql -c "SELECT table_name FROM information_schema.tables..."
├─ Call parseTableNames(tables)
│ └─ Filter headers, separators, footers
└─ Return table names array
Client Request (POST /get-table-data)
↓
[checkAuth Middleware]
└─ Verify JWT → Extract userId
↓
[getTableData Controller]
├─ Validate request body
├─ Call verifyMachine(vpsId, userId, vpsIp)
├─ Call decryptVpsPassword(machine.vps_password)
├─ Create SSHClient → Connect to VPS
├─ Create PostgresSSHHelper(ssh)
├─ pgHelper.getTableData(databaseName, tableName, username)
│ ├─ Validate table name (regex)
│ ├─ SSH: psql -U username -d database -c "SELECT * FROM table" --csv
│ ├─ Check exit code
│ ├─ Parse CSV with PapaParse
│ └─ Return parsed JSON array
└─ Return data to client
Client Request (DELETE /delete-db/:id)
↓
[checkAuth Middleware]
└─ Verify JWT → Extract userId
↓
[deleteDatabaseController]
├─ Extract database ID from params
├─ Query STORAGE_LAYER_DB → deployed_db table (by ID)
├─ Call verifyMachine(vpsId, userId, vpsIp)
├─ Call decryptPassword(machine.vps_password)
├─ Create SSHClient → Connect to VPS
├─ Create PostgresSSHHelper(ssh)
├─ pgHelper.dropDatabase(databaseName)
│ ├─ SSH: Terminate all connections
│ └─ SSH: DROP DATABASE
├─ Delete from STORAGE_LAYER_DB → deployed_db table
└─ Return success response
Purpose: Stores metadata about deployed databases
Schema:
CREATE TABLE deployed_db (
id SERIAL PRIMARY KEY,
db_name VARCHAR NOT NULL,
username VARCHAR NOT NULL,
password VARCHAR NOT NULL,
host VARCHAR NOT NULL,
db_type VARCHAR NOT NULL,
vps_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
status VARCHAR NOT NULL,
created_at TIMESTAMP DEFAULT NOW() NOT NULL
);Columns:
id: Primary key, auto-incrementdb_name: Database nameusername: PostgreSQL usernamepassword: PostgreSQL password (stored in plaintext)host: VPS IP addressdb_type: Database type (e.g., "postgres")vps_id: Foreign key to VPS machineuser_id: Foreign key to user who deployedstatus: Deployment status (e.g., "running")created_at: Timestamp of creation
Indexes: None defined (should add indexes on user_id, vps_id, host)
Relationships:
user_id→ References user in external systemvps_id→ References VPS inDEPLOYMENT_MANAGER_DATABASE_URL
Purpose: Registry of VPS machines and their owners
Schema (inferred from queries):
CREATE TABLE vps_machines (
id INTEGER PRIMARY KEY,
"ownerId" INTEGER NOT NULL,
vps_ip VARCHAR NOT NULL,
vps_password VARCHAR NOT NULL, -- Encrypted
-- Other columns not visible in codebase
);Columns (from code usage):
id: Primary keyownerId: User ID who owns the machinevps_ip: IP address of VPSvps_password: Encrypted password for SSH access
Queries Used:
SELECT * FROM vps_machines WHERE id=$1 AND "ownerId"=$2
-
PORT
- Purpose: Server port number
- Example:
"3000" - Used In:
src/index.ts
-
STORAGE_LAYER_DATABASE_URL
- Purpose: PostgreSQL connection string for metadata database
- Format:
postgresql://user:password@host:port/database - Used In:
src/db/client.ts,drizzle.config.ts
-
DEPLOYMENT_MANAGER_DATABASE_URL
- Purpose: PostgreSQL connection string for VPS registry
- Format:
postgresql://user:password@host:port/database - Used In:
src/db/pool.ts
-
ACCESS_TOKEN_SECRET
- Purpose: JWT secret for token verification
- Example:
"your-secret-key-here" - Used In:
src/jwt/verifyTokens.ts
-
ENCRYPTION_KEY
- Purpose: AES encryption key for VPS passwords
- Example:
"your-encryption-key-here" - Used In:
src/utils/decryptPassword.ts
Location: src/HelperClasses/PostgresHelper.ts:33-41
Issue: Logic is inverted - throws error when database doesn't exist, should create it.
Current Code:
if (dbExists.output.trim() === "0") {
await this.ssh.exec(`sudo -u postgres createdb ${database}`, onLog);
}
throw new Error("Database already exists");Fix: Should only throw if database exists (output === "1").
Location: src/controllers/deleteDatabaseController.ts:12
Issue: Function declares body parameter but doesn't use it. Database details come from database query instead.
Current Code:
const req=body as {dbName:string,vpsIp:string,vpsId:string}
// req is never usedFix: Remove unused body parameter or use it for validation.
Location: Multiple locations in PostgresHelper.ts
Issue: PostgreSQL passwords passed in shell command strings, visible in process list.
Recommendation: Use environment variables or password files.
Location: PostgresHelper.ts:allowRemoteConnections()
Issue: Opens PostgreSQL to all IPs (0.0.0.0/0), major security risk.
Recommendation: Restrict to specific IP ranges or use firewall rules.
Location: Multiple controllers
Issue: Database names and usernames not validated (only table names are).
Recommendation: Add regex validation similar to table names.
Location: All controllers
Issue: Error messages may expose internal system details.
Recommendation: Sanitize error messages before returning to client.
- Implement Rate Limiting: Prevent brute force and DDoS attacks
- Restrict PostgreSQL Access: Use firewall rules and IP whitelisting
- Encrypt PostgreSQL Passwords: Store passwords encrypted in metadata database
- Validate All Inputs: Add regex validation for database names and usernames
- Sanitize Error Messages: Don't expose internal details to clients
- Use Password Files: Avoid passwords in command strings
- Add HTTPS: Ensure all communication is encrypted
- Implement Token Refresh: Add refresh token mechanism
- Fix
createDatabase()Bug: Invert logic - Remove Unused Parameters: Clean up
deleteDatabaseController - Add Database Indexes: Improve query performance
- Add Logging: Implement structured logging
- Add Tests: Unit and integration tests
- Add Type Safety: Stricter TypeScript types
- Error Handling: More specific error types
- Connection Pooling: Already using pools, ensure proper configuration
- Caching: Cache machine verification results
- Async Operations: Optimize sequential SSH commands where possible
- Database Indexes: Add indexes on frequently queried columns
This documentation provides a comprehensive overview of the StorageLayer codebase, including all API routes, functions, commands, security considerations, and data flows. Use this as a reference for understanding, maintaining, and extending the system.