2021-07-03 21:57:53 +02:00
/*
Copyright ( c ) 2021 , Grégory Soutadé
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
* Redistributions of source code must retain the above copyright
notice , this list of conditions and the following d isclaimer .
* Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ` ` AS IS ' ' AND ANY
EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include <unistd.h>
# include <getopt.h>
# include <stdlib.h>
# include <termios.h>
# include <iostream>
# include <ostream>
# include <QFile>
# include <QDir>
# include <QCoreApplication>
# include <QRunnable>
# include <QThreadPool>
# include <libgourou.h>
# include "drmprocessorclientimpl.h"
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
static const char * username = 0 ;
static const char * password = 0 ;
static const char * outputDir = 0 ;
static const char * hobbesVersion = HOBBES_DEFAULT_VERSION ;
static bool randomSerial = false ;
// From http://www.cplusplus.com/articles/E6vU7k9E/
static int getch ( ) {
int ch ;
struct termios t_old , t_new ;
tcgetattr ( STDIN_FILENO , & t_old ) ;
t_new = t_old ;
t_new . c_lflag & = ~ ( ICANON | ECHO ) ;
tcsetattr ( STDIN_FILENO , TCSANOW , & t_new ) ;
ch = getchar ( ) ;
tcsetattr ( STDIN_FILENO , TCSANOW , & t_old ) ;
return ch ;
}
static std : : string getpass ( const char * prompt , bool show_asterisk = false )
{
const char BACKSPACE = 127 ;
const char RETURN = 10 ;
std : : string password ;
unsigned char ch = 0 ;
std : : cout < < prompt ;
while ( ( ch = getch ( ) ) ! = RETURN )
{
if ( ch = = BACKSPACE )
{
if ( password . length ( ) ! = 0 )
{
if ( show_asterisk )
std : : cout < < " \b \b " ;
password . resize ( password . length ( ) - 1 ) ;
}
}
else
{
password + = ch ;
if ( show_asterisk )
std : : cout < < ' * ' ;
}
}
std : : cout < < std : : endl ;
return password ;
}
2021-07-29 21:14:48 +02:00
class ADEPTActivate : public QRunnable
2021-07-03 21:57:53 +02:00
{
public :
2021-07-29 21:14:48 +02:00
ADEPTActivate ( QCoreApplication * app ) :
2021-07-03 21:57:53 +02:00
app ( app )
{
setAutoDelete ( false ) ;
}
void run ( )
{
2021-07-29 21:14:48 +02:00
int ret = 0 ;
2021-07-03 21:57:53 +02:00
try
{
DRMProcessorClientImpl client ;
gourou : : DRMProcessor * processor = gourou : : DRMProcessor : : createDRMProcessor (
& client , randomSerial , outputDir , hobbesVersion ) ;
processor - > signIn ( username , password ) ;
processor - > activateDevice ( ) ;
std : : cout < < username < < " fully signed and device activated in " < < outputDir < < std : : endl ;
} catch ( std : : exception & e )
{
std : : cout < < e . what ( ) < < std : : endl ;
2021-07-29 21:14:48 +02:00
ret = 1 ;
2021-07-03 21:57:53 +02:00
}
2021-07-29 21:14:48 +02:00
this - > app - > exit ( ret ) ;
2021-07-03 21:57:53 +02:00
}
private :
QCoreApplication * app ;
} ;
2021-07-05 20:22:47 +02:00
static void version ( void )
{
std : : cout < < " Current libgourou version : " < < gourou : : DRMProcessor : : VERSION < < std : : endl ;
}
2021-07-03 21:57:53 +02:00
static void usage ( const char * cmd )
{
std : : cout < < " Create new device files used by ADEPT DRM " < < std : : endl ;
2021-12-18 17:43:47 +01:00
std : : cout < < " Usage: " < < cmd < < " (-a|--anonymous) | ( (-u|--username) username [(-p|--password) password] ) [(-O|--output-dir) dir] [(-r|--random-serial)] [(-v|--verbose)] [(-h|--help)] " < < std : : endl < < std : : endl ;
2021-07-03 21:57:53 +02:00
2021-12-18 17:43:47 +01:00
std : : cout < < " " < < " -a|--anonymous " < < " \t " < < " Anonymous account, no need for username/password (Use it only with a DRM removal software) " < < std : : endl ;
2021-07-03 21:57:53 +02:00
std : : cout < < " " < < " -u|--username " < < " \t \t " < < " AdobeID username (ie adobe.com email account) " < < std : : endl ;
std : : cout < < " " < < " -p|--password " < < " \t \t " < < " AdobeID password (asked if not set via command line) " < < std : : endl ;
std : : cout < < " " < < " -O|--output-dir " < < " \t " < < " Optional output directory were to put result (default ./.adept). This directory must not already exists " < < std : : endl ;
std : : cout < < " " < < " -H|--hobbes-version " < < " \t " < < " Force RMSDK version to a specific value (default: version of current librmsdk) " < < std : : endl ;
std : : cout < < " " < < " -r|--random-serial " < < " \t " < < " Generate a random device serial (if not set, it will be dependent of your current configuration) " < < std : : endl ;
std : : cout < < " " < < " -v|--verbose " < < " \t \t " < < " Increase verbosity, can be set multiple times " < < std : : endl ;
2021-11-27 10:29:22 +01:00
std : : cout < < " " < < " -V|--version " < < " \t \t " < < " Display libgourou version " < < std : : endl ;
2021-07-03 21:57:53 +02:00
std : : cout < < " " < < " -h|--help " < < " \t \t " < < " This help " < < std : : endl ;
std : : cout < < std : : endl ;
}
static const char * abspath ( const char * filename )
{
const char * root = getcwd ( 0 , PATH_MAX ) ;
QString fullPath = QString ( root ) + QString ( " / " ) + QString ( filename ) ;
const char * res = strdup ( fullPath . toStdString ( ) . c_str ( ) ) ;
free ( ( void * ) root ) ;
return res ;
}
int main ( int argc , char * * argv )
{
int c , ret = - 1 ;
const char * _outputDir = outputDir ;
int verbose = gourou : : DRMProcessor : : getLogLevel ( ) ;
2021-12-18 17:43:47 +01:00
bool anonymous = false ;
2021-07-03 21:57:53 +02:00
while ( 1 ) {
int option_index = 0 ;
static struct option long_options [ ] = {
2021-12-18 17:43:47 +01:00
{ " anonymous " , no_argument , 0 , ' a ' } ,
2021-07-03 21:57:53 +02:00
{ " username " , required_argument , 0 , ' u ' } ,
{ " password " , required_argument , 0 , ' p ' } ,
{ " output-dir " , required_argument , 0 , ' O ' } ,
{ " hobbes-version " , required_argument , 0 , ' H ' } ,
{ " random-serial " , no_argument , 0 , ' r ' } ,
{ " verbose " , no_argument , 0 , ' v ' } ,
2021-11-27 10:29:22 +01:00
{ " version " , no_argument , 0 , ' V ' } ,
2021-07-03 21:57:53 +02:00
{ " help " , no_argument , 0 , ' h ' } ,
{ 0 , 0 , 0 , 0 }
} ;
2021-12-18 17:43:47 +01:00
c = getopt_long ( argc , argv , " au:p:O:H:rvVh " ,
2021-07-03 21:57:53 +02:00
long_options , & option_index ) ;
if ( c = = - 1 )
break ;
switch ( c ) {
2021-12-18 17:43:47 +01:00
case ' a ' :
anonymous = true ;
break ;
2021-07-03 21:57:53 +02:00
case ' u ' :
username = optarg ;
break ;
case ' p ' :
password = optarg ;
break ;
case ' O ' :
_outputDir = optarg ;
break ;
case ' H ' :
hobbesVersion = optarg ;
break ;
case ' v ' :
verbose + + ;
break ;
2021-07-05 20:22:47 +02:00
case ' V ' :
version ( ) ;
return 0 ;
2021-07-03 21:57:53 +02:00
case ' h ' :
usage ( argv [ 0 ] ) ;
return 0 ;
case ' r ' :
randomSerial = true ;
break ;
default :
usage ( argv [ 0 ] ) ;
return - 1 ;
}
}
gourou : : DRMProcessor : : setLogLevel ( verbose ) ;
2021-12-18 17:43:47 +01:00
if ( ( ! username & & ! anonymous ) | |
( username & & anonymous ) )
2021-07-03 21:57:53 +02:00
{
usage ( argv [ 0 ] ) ;
return - 1 ;
}
2021-12-18 17:43:47 +01:00
if ( anonymous )
{
username = " anonymous " ;
password = " " ;
}
2021-07-03 21:57:53 +02:00
if ( ! _outputDir | | _outputDir [ 0 ] = = 0 )
{
2021-12-18 17:43:47 +01:00
outputDir = strdup ( abspath ( DEFAULT_ADEPT_DIR ) ) ;
2021-07-03 21:57:53 +02:00
}
else
{
// Relative path
if ( _outputDir [ 0 ] = = ' . ' | | _outputDir [ 0 ] ! = ' / ' )
{
QFile file ( _outputDir ) ;
// realpath doesn't works if file/dir doesn't exists
if ( file . exists ( ) )
2021-12-18 17:43:47 +01:00
outputDir = strdup ( realpath ( _outputDir , 0 ) ) ;
2021-07-03 21:57:53 +02:00
else
2021-12-18 17:43:47 +01:00
outputDir = strdup ( abspath ( _outputDir ) ) ;
2021-07-03 21:57:53 +02:00
}
else
outputDir = strdup ( _outputDir ) ;
}
2021-12-18 17:43:47 +01:00
QCoreApplication app ( argc , argv ) ;
QFile file ( outputDir ) ;
if ( file . exists ( ) )
{
int key ;
while ( true )
{
std : : cout < < " !! Warning !! : " < < outputDir < < " already exists. " < < std : : endl ;
std : : cout < < " All your data will be overwrite. Would you like to continue ? [y/N] " < < std : : flush ;
key = getchar ( ) ;
if ( key = = ' n ' | | key = = ' N ' | | key = = ' \n ' | | key = = ' \r ' )
goto end ;
if ( key = = ' y ' | | key = = ' Y ' )
break ;
// Clean STDIN buf
while ( ( key = getchar ( ) ) ! = ' \n ' )
;
}
}
2021-07-03 21:57:53 +02:00
if ( ! password )
{
char prompt [ 128 ] ;
std : : snprintf ( prompt , sizeof ( prompt ) , " Enter password for <%s> : " , username ) ;
std : : string pass = getpass ( ( const char * ) prompt , false ) ;
password = pass . c_str ( ) ;
}
2021-12-18 17:43:47 +01:00
2021-07-29 21:14:48 +02:00
ADEPTActivate activate ( & app ) ;
2021-07-03 21:57:53 +02:00
QThreadPool : : globalInstance ( ) - > start ( & activate ) ;
ret = app . exec ( ) ;
2021-12-18 17:43:47 +01:00
end :
2021-07-03 21:57:53 +02:00
free ( ( void * ) outputDir ) ;
return ret ;
}