diff --git a/src/controllers/process-improved.controller.ts b/src/controllers/process-improved.controller.ts deleted file mode 100644 index aa6e25e..0000000 --- a/src/controllers/process-improved.controller.ts +++ /dev/null @@ -1,449 +0,0 @@ -import { Request, Response } from 'express'; -import { v4 as uuidv4 } from 'uuid'; -import { Database } from '../database'; -import { SignerImprovedService } from '../services/signer-improved'; -import { SessionManager } from '../utils/session-manager'; -import { authTokens } from '../utils/auth-tokens'; -import { ProcessInfo, ProcessData, ProcessRoles, EOfficeStatus } from '../types'; -import { config } from '../config'; -import { Logger } from '../utils/logger'; -import { - AppError, - ErrorCode, - NotFoundError, - ExternalServiceError, - BusinessRuleError -} from '../types/errors'; -import { asyncHandler } from '../middleware/error-handler'; - -export class ProcessImprovedController { - static getUserProcess = asyncHandler(async (req: Request, res: Response): Promise => { - const requestId = req.headers['x-request-id'] as string; - - Logger.info('User process request initiated', { requestId }); - - // Find the full token data which should contain the original idNotUser data - const userAuth = authTokens.find(auth => auth.authToken === req.idNotUser!.authToken); - - if (!userAuth || !userAuth.idNotUser) { - throw new NotFoundError('Données utilisateur non trouvées. Veuillez vous reconnecter.', requestId); - } - - const { pairingId } = req.query; - - // Execute signer operations with retry logic - const processResult = await SignerImprovedService.executeWithRetry( - async (signerClient) => { - return await signerClient.getUserProcessByIdnot(userAuth.idNotUser.idNot); - }, - 'getUserProcessByIdnot', - 3 - ); - - if (!processResult.success) { - throw new ExternalServiceError('Signer', processResult.error?.message || 'Failed to get user process', requestId); - } - - let process: ProcessInfo | null = processResult.data || null; - - if (!process) { - Logger.info('No existing process found, creating new one', { - requestId, - userIdNot: userAuth.idNotUser.idNot - }); - - // Get UUID from database - let uuid: string; - try { - const result = await Database.query('SELECT uid FROM users WHERE "idNot" = $1', [userAuth.idNotUser.idNot]); - uuid = result.rows.length > 0 ? result.rows[0].uid : null; - } catch (error) { - Logger.error('Error fetching UUID by idNot', { - requestId, - error: error instanceof Error ? error.message : 'Unknown error' - }); - uuid = ''; - } - - if (!uuid) { - Logger.info('No existing UUID found in db, generating new one', { requestId }); - uuid = uuidv4(); - } - - const processData: ProcessData = { - uid: uuid, - utype: 'collaborator', - idNot: userAuth.idNotUser.idNot, - office: { - idNot: userAuth.idNotUser.office.idNot, - }, - role: userAuth.idNotUser.role, - office_role: userAuth.idNotUser.office_role, - contact: userAuth.idNotUser.contact, - }; - - const privateFields = Object.keys(processData); - const allFields = [...privateFields, 'roles']; - // Make those fields public - privateFields.splice(privateFields.indexOf('uid'), 1); - privateFields.splice(privateFields.indexOf('utype'), 1); - privateFields.splice(privateFields.indexOf('idNot'), 1); - - // Get pairing ID with retry - const pairingResult = await SignerImprovedService.executeWithRetry( - async (signerClient) => { - return await signerClient.getPairingId(); - }, - 'getPairingId', - 3 - ); - - if (!pairingResult.success) { - throw new ExternalServiceError('Signer', pairingResult.error?.message || 'Failed to get pairing ID', requestId); - } - - const validatorId = pairingResult.data!.pairingId; - - const roles: ProcessRoles = { - owner: { - members: [pairingId as string, validatorId], - validation_rules: [ - { - quorum: 0.1, - fields: allFields, - min_sig_member: 1, - } - ], - storages: [config.defaultStorage] - }, - apophis: { - members: [pairingId as string, validatorId], - validation_rules: [], - storages: [] - } - }; - - // Create process with retry - const createResult = await SignerImprovedService.executeWithRetry( - async (signerClient) => { - return await signerClient.createProcess(processData, privateFields, roles); - }, - 'createProcess', - 3 - ); - - if (!createResult.success) { - throw new ExternalServiceError('Signer', createResult.error?.message || 'Failed to create process', requestId); - } - - Logger.info('Created new process', { - requestId, - processId: createResult.data!.processId - }); - - process = { - processId: createResult.data!.processId || '', - processData: createResult.data!.data - }; - } else { - Logger.info('Using existing process', { - requestId, - processId: process.processId - }); - } - - // Check if process is committed and handle role updates - const processManagementResult = await SignerImprovedService.executeWithRetry( - async (signerClient) => { - const allProcesses = await signerClient.getOwnedProcesses(); - - if (allProcesses && process) { - const processStates = allProcesses.processes[process.processId].states; - const isNotCommited = processStates.length === 2 - && processStates[1].commited_in === processStates[0].commited_in; - - if (isNotCommited) { - Logger.info('Process not committed, committing it', { - requestId, - processId: process.processId - }); - await signerClient.validateState(process.processId, processStates[0].state_id); - } - - // Check pairing ID in roles - let roles: ProcessRoles; - if (isNotCommited) { - const firstState = processStates[0]; - roles = firstState.roles; - } else { - const tip = processStates[processStates.length - 1].commited_in; - const lastState = processStates.findLast((state: any) => state.commited_in !== tip); - roles = lastState.roles; - } - - if (!roles) { - throw new Error('No roles found'); - } else if (!roles['owner']) { - throw new Error('No owner role found'); - } - - if (!roles['owner'].members.includes(req.query.pairingId as string)) { - Logger.info('Adding new pairingId to owner role', { - requestId, - pairingId: req.query.pairingId, - processId: process.processId - }); - - roles['owner'].members.push(req.query.pairingId as string); - const updatedProcessReturn = await signerClient.updateProcess(process.processId, {}, [], roles); - const processId = updatedProcessReturn.updatedProcess.process_id; - const stateId = updatedProcessReturn.updatedProcess.diffs[0].state_id; - await signerClient.notifyUpdate(processId, stateId); - await signerClient.validateState(processId, stateId); - } - } - - return process; - }, - 'processManagement', - 2 - ); - - if (!processManagementResult.success) { - throw new ExternalServiceError('Signer', processManagementResult.error?.message || 'Failed to manage process', requestId); - } - - Logger.info('User process request completed successfully', { - requestId, - processId: process?.processId - }); - - res.json({ - success: true, - data: processManagementResult.data - }); - }); - - static getOfficeProcess = asyncHandler(async (req: Request, res: Response): Promise => { - const requestId = req.headers['x-request-id'] as string; - - Logger.info('Office process request initiated', { requestId }); - - const userAuth = authTokens.find(auth => auth.authToken === req.idNotUser!.authToken); - - if (!userAuth || !userAuth.idNotUser) { - throw new NotFoundError('Données utilisateur non trouvées. Veuillez vous reconnecter.', requestId); - } - - // Check office status - if (userAuth.idNotUser.office.office_status !== EOfficeStatus.ACTIVATED) { - throw new BusinessRuleError('Office not activated', undefined, requestId); - } - - // Get office process with retry - const processResult = await SignerImprovedService.executeWithRetry( - async (signerClient) => { - return await signerClient.getOfficeProcessByIdnot(userAuth.idNotUser.office.idNot); - }, - 'getOfficeProcessByIdnot', - 3 - ); - - if (!processResult.success) { - throw new ExternalServiceError('Signer', processResult.error?.message || 'Failed to get office process', requestId); - } - - let process: ProcessInfo | null = processResult.data || null; - - if (!process) { - Logger.info('No existing office process found, creating new one', { - requestId, - officeIdNot: userAuth.idNotUser.office.idNot - }); - - // Get validator ID with retry - const pairingResult = await SignerImprovedService.executeWithRetry( - async (signerClient) => { - return await signerClient.getPairingId(); - }, - 'getPairingId', - 3 - ); - - if (!pairingResult.success) { - throw new ExternalServiceError('Signer', pairingResult.error?.message || 'Failed to get validator ID', requestId); - } - - const validatorId = pairingResult.data!.pairingId; - if (!validatorId) { - throw new BusinessRuleError('No validator id found', undefined, requestId); - } - - // Get UUID from database - let uuid: string; - try { - const result = await Database.query('SELECT uid FROM offices WHERE "idNot" = $1', [userAuth.idNotUser.office.idNot]); - uuid = result.rows.length > 0 ? result.rows[0].uid : null; - } catch (error) { - Logger.error('Error fetching office UUID by idNot', { - requestId, - error: error instanceof Error ? error.message : 'Unknown error' - }); - uuid = ''; - } - - if (!uuid) { - Logger.info('No existing office UUID found in db, generating new one', { requestId }); - uuid = uuidv4(); - } - - const processData: ProcessData = { - uid: uuid, - utype: 'office', - ...userAuth.idNotUser.office, - }; - - const privateFields = Object.keys(processData); - - const roles: ProcessRoles = { - owner: { - members: [validatorId], - validation_rules: [], - storages: [] - }, - apophis: { - members: [validatorId], - validation_rules: [], - storages: [] - } - }; - - // Create office process with retry - const createResult = await SignerImprovedService.executeWithRetry( - async (signerClient) => { - return await signerClient.createProcess(processData, privateFields, roles); - }, - 'createOfficeProcess', - 3 - ); - - if (!createResult.success) { - throw new ExternalServiceError('Signer', createResult.error?.message || 'Failed to create office process', requestId); - } - - Logger.info('Created new office process', { - requestId, - processId: createResult.data!.processId - }); - - process = { - processId: createResult.data!.processId || '', - processData: createResult.data!.data - }; - } - - Logger.info('Office process request completed successfully', { - requestId, - processId: process?.processId - }); - - res.json({ - success: true, - data: process - }); - }); - - static authenticateClient = asyncHandler(async (req: Request, res: Response): Promise => { - const requestId = req.headers['x-request-id'] as string; - const { pairingId } = req.body; - - if (!pairingId) { - throw new BusinessRuleError('Missing pairingId', undefined, requestId); - } - - Logger.info('Client authentication initiated', { requestId, pairingId }); - - // This should be implemented properly based on your business logic - // For now, just clean up the session - SessionManager.deleteSession(req.session!.id); - - Logger.info('Client authentication completed', { requestId }); - - res.json({ - success: true, - message: 'Client authentication successful', - data: {} - }); - }); - - static getPhoneNumberForEmail = asyncHandler(async (req: Request, res: Response): Promise => { - const requestId = req.headers['x-request-id'] as string; - const { email } = req.body; - - if (!email) { - throw new BusinessRuleError('Missing email', undefined, requestId); - } - - Logger.info('Phone number lookup initiated', { requestId, email }); - - const phoneResult = await SignerImprovedService.executeWithRetry( - async (signerClient) => { - return await signerClient.getPhoneNumberForEmail(email); - }, - 'getPhoneNumberForEmail', - 3 - ); - - if (!phoneResult.success) { - throw new ExternalServiceError('Signer', phoneResult.error?.message || 'Failed to get phone number', requestId); - } - - const phoneNumber = phoneResult.data; - - if (!phoneNumber) { - throw new NotFoundError('No phone number found for this email', requestId); - } - - Logger.info('Phone number lookup completed', { requestId, email }); - - res.json({ - success: true, - message: 'Phone number retrieved successfully', - phoneNumber: phoneNumber - }); - }); - - // Health check endpoint for signer service - static getSignerHealth = asyncHandler(async (req: Request, res: Response): Promise => { - const healthStatus = SignerImprovedService.getHealthStatus(); - - res.json({ - success: true, - data: { - signer: healthStatus, - timestamp: new Date().toISOString() - } - }); - }); - - // Force reconnection endpoint (for debugging/admin use) - static forceSignerReconnect = asyncHandler(async (req: Request, res: Response): Promise => { - const requestId = req.headers['x-request-id'] as string; - - Logger.info('Force signer reconnection requested', { requestId }); - - const reconnectResult = await SignerImprovedService.forceReconnect(); - - if (!reconnectResult.success) { - throw new ExternalServiceError('Signer', reconnectResult.error?.message || 'Failed to reconnect', requestId); - } - - Logger.info('Force signer reconnection completed', { requestId }); - - res.json({ - success: true, - message: 'Signer reconnection initiated', - data: SignerImprovedService.getHealthStatus() - }); - }); -} diff --git a/src/controllers/process.controller.ts b/src/controllers/process.controller.ts index ee6490b..fd956c5 100644 --- a/src/controllers/process.controller.ts +++ b/src/controllers/process.controller.ts @@ -1,326 +1,464 @@ import { Request, Response } from 'express'; import { v4 as uuidv4 } from 'uuid'; import { Database } from '../database'; -import { SignerService } from '../services/signer'; +import { SignerImprovedService } from '../services/signer-improved'; import { SessionManager } from '../utils/session-manager'; import { authTokens } from '../utils/auth-tokens'; import { ProcessInfo, ProcessData, ProcessRoles, EOfficeStatus } from '../types'; import { config } from '../config'; +import { Logger } from '../utils/logger'; +import { + AppError, + ErrorCode, + NotFoundError, + ExternalServiceError, + BusinessRuleError +} from '../types/errors'; +import { asyncHandler } from '../middleware/error-handler'; +import { IdNotController } from './idnot.controller'; export class ProcessController { - static async getUserProcess(req: Request, res: Response): Promise { - console.log('Received request to get user process'); - try { - // Find the full token data which should contain the original idNotUser data - const userAuth = authTokens.find(auth => auth.authToken === req.idNotUser!.authToken); - - if (!userAuth || !userAuth.idNotUser) { - return res.status(404).json({ - success: false, - message: 'Données utilisateur non trouvées. Veuillez vous reconnecter.' - }); - } + static getUserProcess = asyncHandler(async (req: Request, res: Response): Promise => { + const requestId = req.headers['x-request-id'] as string; + + Logger.info('User process request initiated', { requestId }); - const { pairingId } = req.query; - const signerClient = SignerService.getInstance(); + // Find the full token data which should contain the original idNotUser data + const userAuth = authTokens.find(auth => auth.authToken === req.idNotUser!.authToken); + + if (!userAuth || !userAuth.idNotUser) { + throw new NotFoundError('Données utilisateur non trouvées. Veuillez vous reconnecter.', requestId); + } - // Now we ask signer if he knows a process for this office - let process: ProcessInfo | null = await signerClient.getUserProcessByIdnot(userAuth.idNotUser.idNot); + const { pairingId } = req.query; - if (!process) { - console.log('No existing process found in signer, creating a new one'); - // We can use userInfo as data for the process - let uuid: string; - // Try to fetch existing UUID from database by idNot - try { - const result = await Database.query('SELECT uid FROM users WHERE "idNot" = $1', [userAuth.idNotUser.idNot]); - uuid = result.rows.length > 0 ? result.rows[0].uid : null; - } catch (error) { - console.error('Error fetching UUID by idNot:', error); - uuid = ''; - } - - // If no existing UUID found, generate a new one - if (!uuid) { - console.log('No existing UUID found in db, generating a new one'); - uuid = uuidv4(); - } + // Execute signer operations with retry logic + const processResult = await SignerImprovedService.executeWithRetry( + async (signerClient) => { + return await signerClient.getUserProcessByIdnot(userAuth.idNotUser.idNot); + }, + 'getUserProcessByIdnot', + 3 + ); - const processData: ProcessData = { - uid: uuid, - utype: 'collaborator', - idNot: userAuth.idNotUser.idNot, - office: { - idNot: userAuth.idNotUser.office.idNot, - }, - role: userAuth.idNotUser.role, - office_role: userAuth.idNotUser.office_role, - contact: userAuth.idNotUser.contact, - }; + if (!processResult.success) { + throw new ExternalServiceError('Signer', processResult.error?.message || 'Failed to get user process', requestId); + } - console.log('processData', processData); + let process: ProcessInfo | null = processResult.data || null; - const privateFields = Object.keys(processData); - const allFields = [...privateFields, 'roles']; - // Make those fields public - privateFields.splice(privateFields.indexOf('uid'), 1); - privateFields.splice(privateFields.indexOf('utype'), 1); - privateFields.splice(privateFields.indexOf('idNot'), 1); - - const getPairingIdResponse = await signerClient.getPairingId(); - const validatorId = getPairingIdResponse.pairingId; - - const roles: ProcessRoles = { - owner: { - members: [pairingId as string, validatorId], - validation_rules: [ - { - quorum: 0.1, - fields: allFields, - min_sig_member: 1, - } - ], - storages: [config.defaultStorage] - }, - apophis: { - members: [pairingId as string, validatorId], - validation_rules: [], - storages: [] - } - }; - - const newCollaboratorProcess = await signerClient.createProcess(processData, privateFields, roles); - console.log('Created new process:', newCollaboratorProcess); - // The createProcess returns a ServerResponse, we need to extract the process info - process = { processId: newCollaboratorProcess.processId, processData: newCollaboratorProcess.data }; - } else { - console.log('Using process:', process.processId); - } - - // We check that the process is commited, we do it if that's not the case - const allProcesses = await signerClient.getOwnedProcesses(); - if (allProcesses && process) { - const processStates = allProcesses.processes[process.processId].states; - const isNotCommited = processStates.length === 2 - && processStates[1].commited_in === processStates[0].commited_in; - if (isNotCommited) { - console.log('Process is not commited, committing it'); - await signerClient.validateState(process.processId, processStates[0].state_id); - } - - // We check that the pairingId is indeed part of the roles - let roles: ProcessRoles; - if (isNotCommited) { - // We take the first state - const firstState = processStates[0]; - roles = firstState.roles; - } else { - const tip = processStates[processStates.length - 1].commited_in; - const lastState = processStates.findLast((state: any) => state.commited_in !== tip); - roles = lastState.roles; - } - - if (!roles) { - throw new Error('No roles found'); - } else if (!roles['owner']) { - throw new Error('No owner role found'); - } - - if (!roles['owner'].members.includes(req.query.pairingId as string)) { - // We add the new pairingId to the owner role and commit - console.log('Adding new pairingId', req.query.pairingId, 'to owner role'); - roles['owner'].members.push(req.query.pairingId as string); - const updatedProcessReturn = await signerClient.updateProcess(process.processId, {}, [], roles); - const processId = updatedProcessReturn.updatedProcess.process_id; - const stateId = updatedProcessReturn.updatedProcess.diffs[0].state_id; - await signerClient.notifyUpdate(processId, stateId); - await signerClient.validateState(processId, stateId); - } - } else { - throw new Error('No processes found'); - } - - // Return the stored idNotUser data without the authToken - res.json({ - success: true, - data: process + if (!process) { + Logger.info('No existing process found, creating new one', { + requestId, + userIdNot: userAuth.idNotUser.idNot }); - } catch (error: any) { - res.status(500).json({ - success: false, - message: 'Erreur lors de la récupération des données utilisateur', - error: error.message + // Get UUID from database + let uuid: string; + try { + const result = await Database.query('SELECT uid FROM users WHERE "idNot" = $1', [userAuth.idNotUser.idNot]); + uuid = result.rows.length > 0 ? result.rows[0].uid : null; + } catch (error) { + Logger.error('Error fetching UUID by idNot', { + requestId, + error: error instanceof Error ? error.message : 'Unknown error' + }); + uuid = ''; + } + + if (!uuid) { + Logger.info('No existing UUID found in db, generating new one', { requestId }); + uuid = uuidv4(); + } + + const processData: ProcessData = { + uid: uuid, + utype: 'collaborator', + idNot: userAuth.idNotUser.idNot, + office: { + idNot: userAuth.idNotUser.office.idNot, + }, + role: userAuth.idNotUser.role, + office_role: userAuth.idNotUser.office_role, + contact: userAuth.idNotUser.contact, + }; + + const privateFields = Object.keys(processData); + const allFields = [...privateFields, 'roles']; + // Make those fields public + privateFields.splice(privateFields.indexOf('uid'), 1); + privateFields.splice(privateFields.indexOf('utype'), 1); + privateFields.splice(privateFields.indexOf('idNot'), 1); + + // Get pairing ID with retry + const pairingResult = await SignerImprovedService.executeWithRetry( + async (signerClient) => { + return await signerClient.getPairingId(); + }, + 'getPairingId', + 3 + ); + + if (!pairingResult.success) { + throw new ExternalServiceError('Signer', pairingResult.error?.message || 'Failed to get pairing ID', requestId); + } + + const validatorId = pairingResult.data!.pairingId; + + const roles: ProcessRoles = { + owner: { + members: [pairingId as string, validatorId], + validation_rules: [ + { + quorum: 0.1, + fields: allFields, + min_sig_member: 1, + } + ], + storages: [config.defaultStorage] + }, + apophis: { + members: [pairingId as string, validatorId], + validation_rules: [], + storages: [] + } + }; + + // Create process with retry + const createResult = await SignerImprovedService.executeWithRetry( + async (signerClient) => { + return await signerClient.createProcess(processData, privateFields, roles); + }, + 'createProcess', + 3 + ); + + if (!createResult.success) { + throw new ExternalServiceError('Signer', createResult.error?.message || 'Failed to create process', requestId); + } + + Logger.info('Created new process', { + requestId, + processId: createResult.data!.processId, + processData: createResult.data!.processData + }); + + process = { + processId: createResult.data!.processId || '', + processData: createResult.data!.data + }; + } else { + Logger.info('Using existing process', { + requestId, + processId: process.processId }); } - } - static async getOfficeProcess(req: Request, res: Response): Promise { - console.log('Received request to get office process'); - try { - // Find the full token data which should contain the original idNotUser data - const userAuth = authTokens.find(auth => auth.authToken === req.idNotUser!.authToken); - - if (!userAuth || !userAuth.idNotUser) { - return res.status(404).json({ - success: false, - message: 'Données utilisateur non trouvées. Veuillez vous reconnecter.' - }); - } + // Check if process is committed and handle role updates + const processManagementResult = await SignerImprovedService.executeWithRetry( + async (signerClient) => { + const allProcesses = await signerClient.getOwnedProcesses(); + + if (allProcesses && process) { + const processStates = allProcesses.processes[process.processId].states; + const isNotCommited = processStates.length === 2 + && processStates[1].commited_in === processStates[0].commited_in; + + if (isNotCommited) { + Logger.info('Process not committed, committing it', { + requestId, + processId: process.processId + }); + await signerClient.validateState(process.processId, processStates[0].state_id); + } - // If office is not ACTIVATED, we return a 404 error - if (userAuth.idNotUser.office.office_status !== EOfficeStatus.ACTIVATED) { - return res.status(404).json({ - success: false, - message: 'Office not activated' - }); - } + // Check pairing ID in roles + let roles: ProcessRoles; + if (isNotCommited) { + const firstState = processStates[0]; + roles = firstState.roles; + } else { + const tip = processStates[processStates.length - 1].commited_in; + const lastState = processStates.findLast((state: any) => state.commited_in !== tip); + roles = lastState.roles; + } - const signerClient = SignerService.getInstance(); + if (!roles) { + throw new Error('No roles found'); + } else if (!roles['owner']) { + throw new Error('No owner role found'); + } - // Now we ask signer if he knows a process for this office - let process: ProcessInfo | null = await signerClient.getOfficeProcessByIdnot(userAuth.idNotUser.office.idNot); - - if (!process) { - // Let's create it - // We directly use the office info as process data - const getPairingIdResponse = await signerClient.getPairingId(); - const validatorId = getPairingIdResponse.pairingId; - if (!validatorId) { - return res.status(400).json({ - success: false, - message: 'No validator id found' - }); - } - - let uuid: string; - // Try to fetch existing UUID from database by idNot - try { - const result = await Database.query('SELECT uid FROM offices WHERE "idNot" = $1', [userAuth.idNotUser.office.idNot]); - uuid = result.rows.length > 0 ? result.rows[0].uid : null; - } catch (error) { - console.error('Error fetching UUID by idNot:', error); - uuid = ''; + if (!roles['owner'].members.includes(req.query.pairingId as string)) { + Logger.info('Adding new pairingId to owner role', { + requestId, + pairingId: req.query.pairingId, + processId: process.processId + }); + + roles['owner'].members.push(req.query.pairingId as string); + const updatedProcessReturn = await signerClient.updateProcess(process.processId, {}, [], roles); + const processId = updatedProcessReturn.updatedProcess.process_id; + const stateId = updatedProcessReturn.updatedProcess.diffs[0].state_id; + await signerClient.notifyUpdate(processId, stateId); + await signerClient.validateState(processId, stateId); + } } - // If no existing UUID found, generate a new one - if (!uuid) { - console.log('No existing UUID found in db, generating a new one'); - uuid = uuidv4(); - } + return process; + }, + 'processManagement', + 2 + ); - const processData: ProcessData = { - uid: uuidv4(), - utype: 'office', - ...userAuth.idNotUser.office, - }; - - console.log('processData', processData); - - const privateFields = Object.keys(processData); - - const roles: ProcessRoles = { - owner: { - members: [validatorId], - validation_rules: [], - storages: [] - }, - apophis: { - members: [validatorId], - validation_rules: [], - storages: [] - } - }; - const newOfficeProcess = await signerClient.createProcess(processData, privateFields, roles); - process = { processId: newOfficeProcess.processId, processData: newOfficeProcess.data }; - console.log('Created new office process:', process); - } - - // We check that the process is commited, we do it if that's not the case - const allProcesses = await signerClient.getOwnedProcesses(); - if (allProcesses && process) { - const processStates = allProcesses.processes[process.processId].states; - const isNotCommited = processStates.length === 2 - && processStates[1].commited_in === processStates[0].commited_in; - if (isNotCommited) { - console.log('Process is not commited, committing it'); - await signerClient.validateState(process.processId, processStates[0].state_id); - } - } else { - throw new Error('No processes found'); - } - - // Return the stored idNotUser data without the authToken - res.json({ - success: true, - data: process - }); - - } catch (error: any) { - res.status(500).json({ - success: false, - message: 'Erreur lors de la récupération des données utilisateur', - error: error.message - }); + if (!processManagementResult.success) { + throw new ExternalServiceError('Signer', processManagementResult.error?.message || 'Failed to manage process', requestId); } - } - static async authenticateClient(req: Request, res: Response): Promise { + Logger.info('User process request completed successfully', { + requestId, + processId: process?.processId + }); + + res.json({ + success: true, + data: processManagementResult.data + }); + }); + + static getOfficeProcess = asyncHandler(async (req: Request, res: Response): Promise => { + const requestId = req.headers['x-request-id'] as string; + + Logger.info('Office process request initiated', { requestId }); + + const userAuth = authTokens.find(auth => auth.authToken === req.idNotUser!.authToken); + + if (!userAuth || !userAuth.idNotUser) { + throw new NotFoundError('Données utilisateur non trouvées. Veuillez vous reconnecter.', requestId); + } + + // Check office status + if (userAuth.idNotUser.office.office_status !== EOfficeStatus.ACTIVATED) { + throw new BusinessRuleError('Office not activated', undefined, requestId); + } + + // Get office process with retry + const processResult = await SignerImprovedService.executeWithRetry( + async (signerClient) => { + return await signerClient.getOfficeProcessByIdnot(userAuth.idNotUser.office.idNot); + }, + 'getOfficeProcessByIdnot', + 3 + ); + + if (!processResult.success) { + throw new ExternalServiceError('Signer', processResult.error?.message || 'Failed to get office process', requestId); + } + + let process: ProcessInfo | null = processResult.data || null; + + if (!process) { + Logger.info('No existing office process found, creating new one', { + requestId, + officeIdNot: userAuth.idNotUser.office.idNot + }); + + // Get validator ID with retry + const pairingResult = await SignerImprovedService.executeWithRetry( + async (signerClient) => { + return await signerClient.getPairingId(); + }, + 'getPairingId', + 3 + ); + + if (!pairingResult.success) { + throw new ExternalServiceError('Signer', pairingResult.error?.message || 'Failed to get validator ID', requestId); + } + + const validatorId = pairingResult.data!.pairingId; + if (!validatorId) { + throw new BusinessRuleError('No validator id found', undefined, requestId); + } + + // Get UUID from database + let uuid: string; + try { + const result = await Database.query('SELECT uid FROM offices WHERE "idNot" = $1', [userAuth.idNotUser.office.idNot]); + uuid = result.rows.length > 0 ? result.rows[0].uid : null; + } catch (error) { + Logger.error('Error fetching office UUID by idNot', { + requestId, + error: error instanceof Error ? error.message : 'Unknown error' + }); + uuid = ''; + } + + if (!uuid) { + Logger.info('No existing office UUID found in db, generating new one', { requestId }); + uuid = uuidv4(); + } + + const processData: ProcessData = { + uid: uuid, + utype: 'office', + ...userAuth.idNotUser.office, + }; + + const privateFields = Object.keys(processData); + const allFields = [...privateFields, 'roles']; + + // No need for public fields? + + const roles: ProcessRoles = { + owner: { + members: [validatorId], + validation_rules: [{ + quorum: 0.1, + fields: allFields, + min_sig_member: 1, + }], + storages: [config.defaultStorage] + }, + apophis: { + members: [validatorId], + validation_rules: [], + storages: [] + } + }; + + // Create office process with retry + const createResult = await SignerImprovedService.executeWithRetry( + async (signerClient) => { + return await signerClient.createProcess(processData, privateFields, roles); + }, + 'createOfficeProcess', + 3 + ); + + if (!createResult.success) { + throw new ExternalServiceError('Signer', createResult.error?.message || 'Failed to create office process', requestId); + } + + Logger.info('Created new office process', { process: createResult.data }); + + // Use the idnot number to identify all active members of the office + const officeCollaborators = await IdNotController.getOfficeRattachements(userAuth.idNotUser.office.idNot); + Logger.debug('Office collaborators', { officeCollaborators }); + + // Logger.info('Created new office process', { + // requestId, + // processId: createResult.data!.processId + // }); + + process = { + processId: createResult.data!.processCreated.processId || '', + processData: createResult.data!.processData + }; + } + + Logger.info('Office process request completed successfully', { + requestId, + processId: process?.processId + }); + + res.json({ + success: true, + data: process + }); + }); + + static authenticateClient = asyncHandler(async (req: Request, res: Response): Promise => { + const requestId = req.headers['x-request-id'] as string; const { pairingId } = req.body; if (!pairingId) { - return res.status(400).json({ - success: false, - message: 'Missing pairingId' - }); + throw new BusinessRuleError('Missing pairingId', undefined, requestId); } - try { - // This should be implemented properly based on your business logic - // const result = await signerClient.updateProcess(processId, newData, privateFields || [], roles || null); - - // Clean up the session after successful update - SessionManager.deleteSession(req.session!.id); - - res.json({ - success: true, - message: 'Client authentication successful', - data: {} - }); - } catch (error: any) { - console.error('Client authentication error:', error); - res.status(500).json({ - success: false, - message: 'Error during client authentication', - error: error.message - }); - } - } + Logger.info('Client authentication initiated', { requestId, pairingId }); - static async getPhoneNumberForEmail(req: Request, res: Response): Promise { + // This should be implemented properly based on your business logic + // For now, just clean up the session + SessionManager.deleteSession(req.session!.id); + + Logger.info('Client authentication completed', { requestId }); + + res.json({ + success: true, + message: 'Client authentication successful', + data: {} + }); + }); + + static getPhoneNumberForEmail = asyncHandler(async (req: Request, res: Response): Promise => { + const requestId = req.headers['x-request-id'] as string; const { email } = req.body; if (!email) { - return res.status(400).json({ - success: false, - message: 'Missing email' - }); + throw new BusinessRuleError('Missing email', undefined, requestId); } - const signerClient = SignerService.getInstance(); - const phoneNumber = await signerClient.getPhoneNumberForEmail(email); + Logger.info('Phone number lookup initiated', { requestId, email }); + + const phoneResult = await SignerImprovedService.executeWithRetry( + async (signerClient) => { + return await signerClient.getPhoneNumberForEmail(email); + }, + 'getPhoneNumberForEmail', + 3 + ); + + if (!phoneResult.success) { + throw new ExternalServiceError('Signer', phoneResult.error?.message || 'Failed to get phone number', requestId); + } + + const phoneNumber = phoneResult.data; if (!phoneNumber) { - return res.status(400).json({ - success: false, - message: 'No phone number found for this email' - }); + throw new NotFoundError('No phone number found for this email', requestId); } + Logger.info('Phone number lookup completed', { requestId, email, phoneResult }); + res.json({ success: true, message: 'Phone number retrieved successfully', phoneNumber: phoneNumber }); - } + }); + + // Health check endpoint for signer service + static getSignerHealth = asyncHandler(async (req: Request, res: Response): Promise => { + const healthStatus = SignerImprovedService.getHealthStatus(); + + res.json({ + success: true, + data: { + signer: healthStatus, + timestamp: new Date().toISOString() + } + }); + }); + + // Force reconnection endpoint (for debugging/admin use) + static forceSignerReconnect = asyncHandler(async (req: Request, res: Response): Promise => { + const requestId = req.headers['x-request-id'] as string; + + Logger.info('Force signer reconnection requested', { requestId }); + + const reconnectResult = await SignerImprovedService.forceReconnect(); + + if (!reconnectResult.success) { + throw new ExternalServiceError('Signer', reconnectResult.error?.message || 'Failed to reconnect', requestId); + } + + Logger.info('Force signer reconnection completed', { requestId }); + + res.json({ + success: true, + message: 'Signer reconnection initiated', + data: SignerImprovedService.getHealthStatus() + }); + }); } diff --git a/src/routes/process-improved.routes.ts b/src/routes/process-improved.routes.ts deleted file mode 100644 index d68edb0..0000000 --- a/src/routes/process-improved.routes.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Router } from 'express'; -import { ProcessImprovedController } from '../controllers/process-improved.controller'; -import { authenticateIdNot } from '../middleware/auth'; -import { validateSession } from '../middleware/session'; - -const router = Router(); - -// Health check routes (public) -router.get('/health/signer', ProcessImprovedController.getSignerHealth); -router.post('/admin/signer/reconnect', ProcessImprovedController.forceSignerReconnect); // Should be protected in production - -// IdNot protected routes -router.get('/user', authenticateIdNot, ProcessImprovedController.getUserProcess); -router.get('/office', authenticateIdNot, ProcessImprovedController.getOfficeProcess); - -// Customer auth routes (session protected) -router.post('/customer/auth/client-auth', validateSession, ProcessImprovedController.authenticateClient); -router.post('/customer/auth/get-phone-number-for-email', validateSession, ProcessImprovedController.getPhoneNumberForEmail); - -export { router as processImprovedRoutes }; diff --git a/src/routes/process.routes.ts b/src/routes/process.routes.ts index 6d11469..3fc3480 100644 --- a/src/routes/process.routes.ts +++ b/src/routes/process.routes.ts @@ -5,6 +5,10 @@ import { validateSession } from '../middleware/session'; const router = Router(); +// Health check routes (public) +router.get('/health/signer', ProcessController.getSignerHealth); +router.post('/admin/signer/reconnect', ProcessController.forceSignerReconnect); // Should be protected in production + // IdNot protected routes router.get('/user', authenticateIdNot, ProcessController.getUserProcess); router.get('/office', authenticateIdNot, ProcessController.getOfficeProcess);