2018-12-19 10:54:33 -08:00
'use strict' ;
exports = module . exports = {
2021-05-01 11:21:09 -07:00
createTicket ,
2018-12-19 11:47:15 -08:00
2021-05-01 11:21:09 -07:00
getRemoteSupport ,
enableRemoteSupport ,
2020-02-05 14:30:56 -08:00
2021-05-01 11:21:09 -07:00
canCreateTicket ,
canEnableRemoteSupport
2018-12-19 10:54:33 -08:00
} ;
2021-08-18 15:54:53 -07:00
const appstore = require ( '../appstore.js' ) ,
2018-12-19 10:54:33 -08:00
assert = require ( 'assert' ) ,
2021-09-30 09:50:30 -07:00
AuditSource = require ( '../auditsource.js' ) ,
2020-02-04 13:07:26 -08:00
constants = require ( '../constants.js' ) ,
2018-12-19 10:54:33 -08:00
HttpError = require ( 'connect-lastmile' ) . HttpError ,
HttpSuccess = require ( 'connect-lastmile' ) . HttpSuccess ,
2021-08-18 15:54:53 -07:00
safe = require ( 'safetydance' ) ,
2020-02-05 14:30:56 -08:00
settings = require ( '../settings.js' ) ,
2018-12-19 11:47:15 -08:00
support = require ( '../support.js' ) ,
2018-12-19 10:54:33 -08:00
_ = require ( 'underscore' ) ;
2021-08-18 15:54:53 -07:00
async function canCreateTicket ( req , res , next ) {
const [ error , supportConfig ] = await safe ( settings . getSupportConfig ( ) ) ;
if ( error ) return next ( new HttpError ( 503 , error . message ) ) ;
2020-02-05 14:30:56 -08:00
2021-08-18 15:54:53 -07:00
if ( ! supportConfig . submitTickets ) return next ( new HttpError ( 405 , 'feature disabled by admin' ) ) ;
2020-02-05 14:30:56 -08:00
2021-08-18 15:54:53 -07:00
next ( ) ;
2020-02-05 14:30:56 -08:00
}
2021-08-18 15:54:53 -07:00
async function createTicket ( req , res , next ) {
2018-12-19 10:54:33 -08:00
assert . strictEqual ( typeof req . user , 'object' ) ;
2019-10-15 11:48:20 -07:00
const VALID _TYPES = [ 'feedback' , 'ticket' , 'app_missing' , 'app_error' , 'upgrade_request' , 'email_error' ] ;
2018-12-19 10:54:33 -08:00
if ( typeof req . body . type !== 'string' || ! req . body . type ) return next ( new HttpError ( 400 , 'type must be string' ) ) ;
if ( VALID _TYPES . indexOf ( req . body . type ) === - 1 ) return next ( new HttpError ( 400 , 'unknown type' ) ) ;
if ( typeof req . body . subject !== 'string' || ! req . body . subject ) return next ( new HttpError ( 400 , 'subject must be string' ) ) ;
if ( typeof req . body . description !== 'string' || ! req . body . description ) return next ( new HttpError ( 400 , 'description must be string' ) ) ;
if ( req . body . appId && typeof req . body . appId !== 'string' ) return next ( new HttpError ( 400 , 'appId must be string' ) ) ;
2019-10-15 11:39:44 -07:00
if ( req . body . altEmail && typeof req . body . altEmail !== 'string' ) return next ( new HttpError ( 400 , 'altEmail must be string' ) ) ;
2020-10-05 15:20:14 +02:00
if ( req . body . enableSshSupport && typeof req . body . enableSshSupport !== 'boolean' ) return next ( new HttpError ( 400 , 'enableSshSupport must be a boolean' ) ) ;
2018-12-19 10:54:33 -08:00
2021-08-18 15:54:53 -07:00
const [ error , supportConfig ] = await safe ( settings . getSupportConfig ( ) ) ;
if ( error ) return next ( new HttpError ( 503 , ` Error getting support config: ${ error . message } ` ) ) ;
if ( supportConfig . email !== constants . SUPPORT _EMAIL ) return next ( new HttpError ( 503 , 'Sending to non-cloudron email not implemented yet' ) ) ;
2020-02-05 14:30:56 -08:00
2021-09-30 09:50:30 -07:00
const [ ticketError , result ] = await safe ( appstore . createTicket ( _ . extend ( { } , req . body , { email : req . user . email , displayName : req . user . displayName } ) , AuditSource . fromRequest ( req ) ) ) ;
2021-08-18 15:54:53 -07:00
if ( ticketError ) return next ( new HttpError ( 503 , ` Error contacting cloudron.io: ${ error . message } . Please email ${ constants . SUPPORT _EMAIL } ` ) ) ;
2020-02-05 14:30:56 -08:00
2021-08-18 15:54:53 -07:00
next ( new HttpSuccess ( 201 , result ) ) ;
2020-02-05 14:30:56 -08:00
}
2021-08-18 15:54:53 -07:00
async function canEnableRemoteSupport ( req , res , next ) {
const [ error , supportConfig ] = await safe ( settings . getSupportConfig ( ) ) ;
if ( error ) return next ( new HttpError ( 503 , error . message ) ) ;
2020-02-05 14:30:56 -08:00
2021-08-18 15:54:53 -07:00
if ( ! supportConfig . remoteSupport ) return next ( new HttpError ( 405 , 'feature disabled by admin' ) ) ;
2018-12-19 10:54:33 -08:00
2021-10-07 17:17:45 +02:00
const SSHD _CONFIG _FILE = '/etc/ssh/sshd_config' ;
const sshdConfig = safe . fs . readFileSync ( SSHD _CONFIG _FILE , 'utf8' ) ;
if ( ! sshdConfig ) return next ( new HttpError ( 412 , ` Failed to read file ${ SSHD _CONFIG _FILE } ` ) ) ;
2021-12-26 17:51:05 +01:00
// only check for PermitRootLogin if we want to enable remote support
if ( req . body . enable && ! sshdConfig . split ( '\n' ) . find ( function ( line ) { return line . search ( /^PermitRootLogin.*yes/ ) !== - 1 ; } ) ) return next ( new HttpError ( 417 , ` Set "PermitRootLogin yes" in ${ SSHD _CONFIG _FILE } ` ) ) ;
2021-10-07 17:04:20 +02:00
2021-08-18 15:54:53 -07:00
next ( ) ;
2018-12-19 10:54:33 -08:00
}
2018-12-19 11:47:15 -08:00
2021-08-18 15:54:53 -07:00
async function enableRemoteSupport ( req , res , next ) {
2018-12-19 11:47:15 -08:00
assert . strictEqual ( typeof req . body , 'object' ) ;
if ( typeof req . body . enable !== 'boolean' ) return next ( new HttpError ( 400 , 'enabled is required' ) ) ;
2021-09-30 09:50:30 -07:00
const [ error ] = await safe ( support . enableRemoteSupport ( req . body . enable , AuditSource . fromRequest ( req ) ) ) ;
2021-08-18 15:54:53 -07:00
if ( error ) return next ( new HttpError ( 503 , 'Error enabling remote support. Try running "cloudron-support --enable-ssh" on the server' ) ) ;
2018-12-19 11:47:15 -08:00
2021-08-18 15:54:53 -07:00
next ( new HttpSuccess ( 202 , { } ) ) ;
2018-12-19 11:47:15 -08:00
}
2021-08-18 15:54:53 -07:00
async function getRemoteSupport ( req , res , next ) {
const [ error , enabled ] = await safe ( support . getRemoteSupport ( ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
2018-12-19 11:47:15 -08:00
2021-08-18 15:54:53 -07:00
next ( new HttpSuccess ( 200 , { enabled } ) ) ;
2018-12-19 11:47:15 -08:00
}