diff --git a/README.md b/README.md index 35eee2a..ff8eecf 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,12 @@ grive -a A URL should be printed. Go to the link. You will need to login to your Google account if you haven't done so. After granting the permission to Grive, the -browser will show you an authenication code. Copy-and-paste that to the -standard input of Grive. +authorization code will be forwarded to the Grive application and you will be +redirected to a localhost web page confirming the authorization. -If everything works fine, Grive will create .grive and .grive_state files in your -current directory. It will also start downloading files from your Google Drive to -your current directory. +If everything works fine, Grive will create .grive and .grive\_state files in +your current directory. It will also start downloading files from your Google +Drive to your current directory. To resync the direcory, run `grive` in the folder. @@ -154,6 +154,7 @@ You need the following libraries: - libgcrypt - Boost (Boost filesystem, program_options, regex, unit_test_framework and system are required) - expat +- libcpprest-dev There are also some optional dependencies: - CppUnit (for unit tests) @@ -165,16 +166,17 @@ these packages: sudo apt-get install git cmake build-essential libgcrypt20-dev libyajl-dev \ libboost-all-dev libcurl4-openssl-dev libexpat1-dev libcppunit-dev binutils-dev \ - debhelper zlib1g-dev dpkg-dev pkg-config + debhelper zlib1g-dev dpkg-dev pkg-config libcpprest-dev Fedora: - sudo dnf install git cmake libgcrypt-devel gcc-c++ libstdc++ yajl-devel boost-devel libcurl-devel expat-devel binutils zlib + sudo dnf install git cmake libgcrypt-devel gcc-c++ libstdc++ yajl-devel boost-devel libcurl-devel expat-devel binutils zlib cpprest-devel FreeBSD: pkg install git cmake boost-libs yajl libgcrypt pkgconf cppunit libbfd + cpprestsdk ### Build Debian packages diff --git a/debian/control b/debian/control index 150f688..65b4f91 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: grive2 Section: net Priority: optional Maintainer: Vitaliy Filippov -Build-Depends: debhelper, cmake, pkg-config, zlib1g-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libboost-filesystem-dev, libboost-program-options-dev, libboost-test-dev, libboost-regex-dev, libexpat1-dev, libgcrypt-dev, libyajl-dev +Build-Depends: debhelper, cmake, pkg-config, zlib1g-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libboost-filesystem-dev, libboost-program-options-dev, libboost-test-dev, libboost-regex-dev, libexpat1-dev, libgcrypt-dev, libyajl-dev, libcpprest-dev Standards-Version: 3.9.6 Homepage: https://yourcmc.ru/wiki/Grive2 diff --git a/grive/CMakeLists.txt b/grive/CMakeLists.txt index ac5b781..def223d 100644 --- a/grive/CMakeLists.txt +++ b/grive/CMakeLists.txt @@ -1,6 +1,8 @@ project( grive ) find_package(Boost COMPONENTS program_options REQUIRED) +find_package(cpprestsdk REQUIRED) +find_package(OpenSSL REQUIRED) include_directories( ${grive_SOURCE_DIR}/../libgrive/src @@ -18,6 +20,8 @@ add_executable( grive_executable target_link_libraries( grive_executable grive + OpenSSL::Crypto + cpprestsdk::cpprest ) set(DEFAULT_APP_ID "615557989097-i93d4d1ojpen0m0dso18ldr6orjkidgf.apps.googleusercontent.com") diff --git a/grive/src/main.cc b/grive/src/main.cc index 54d5560..9e89285 100644 --- a/grive/src/main.cc +++ b/grive/src/main.cc @@ -45,13 +45,21 @@ #include #include #include +#include + +#include +#include const std::string default_id = APP_ID ; const std::string default_secret = APP_SECRET ; +const std::string default_redirect_uri = "http://localhost:9898" ; using namespace gr ; namespace po = boost::program_options; +using namespace web::http::experimental::listener; +using namespace web::http; + // libgcrypt insist this to be done in application, not library void InitGCrypt() { @@ -101,6 +109,63 @@ void InitLog( const po::variables_map& vm ) LogBase::Inst( comp_log.release() ) ; } +// AuthCode reads an authorization code from the "code" query parameter passed +// via client-side redirect to the redirect_uri specified in uri +std::string AuthCode( std::string uri ) +{ + // Set up an HTTP listener that is waiting for Google + // to hit the specified local URI with the authorization + // code response + http_listener listener(uri); + listener. + open(). + then([uri]() { + std::cout + << "\n" + << "Listening on " << uri << " for an authorization code from Google" + << std::endl; + }). + wait(); + + // Set up a promise to read the authorization code from the + // redirect + std::promise result; + listener.support(methods::GET, [&result] (http_request req) { + // Extract the "code" query parameter + auto params = uri::split_query(req.request_uri().query()); + auto found_code = params.find("code"); + + // If auth code is missing, respond with basic web page + // containing error message + if (found_code == params.end()) { + std::cout + << "request received without auth code: " << req.absolute_uri().to_string() + << std::endl; + auto msg = + "grive2 authorization code redirect missing 'code' query parameter.\n\n" + "Try the auth flow again."; + req.reply(status_codes::BadRequest, msg); + } + + // If found, respond with basic web page telling user to close + // the window and pass the actual code back to the rest of the + // application + auto code = found_code->second; + std::cout << "received authorization code" << std::endl; + auto msg = "Received grive2 authorization code. You may now close this window."; + req.reply(status_codes::OK, msg).wait(); + result.set_value(code); + }); + + // Block until we receive an auth code + std::string code = result.get_future().get(); + + // Having received the code, block until listener is shut down + listener.close().wait(); + + return code; +} + int Main( int argc, char **argv ) { InitGCrypt() ; @@ -115,6 +180,7 @@ int Main( int argc, char **argv ) ( "secret,e", po::value(), "Authentication secret") ( "print-url", "Only print url for request") ( "path,p", po::value(), "Path to working copy root") + ( "redirect-uri", po::value(), "local URI on which to listen for auth redirect") ( "dir,s", po::value(), "Single subdirectory to sync") ( "verbose,V", "Verbose mode. Enable more messages than normal.") ( "log-http", po::value(), "Log all HTTP responses in this file for debugging.") @@ -183,6 +249,9 @@ int Main( int argc, char **argv ) std::string secret = vm.count( "secret" ) > 0 ? vm["secret"].as() : default_secret ; + std::string uri = vm.count( "redirect-uri" ) > 0 + ? vm["redirect-uri"].as() + : default_redirect_uri ; OAuth2 token( http.get(), id, secret ) ; @@ -194,16 +263,11 @@ int Main( int argc, char **argv ) std::cout << "-----------------------\n" - << "Please go to this URL and get an authentication code:\n\n" + << "Please go to this URL to authorize the app:\n\n" << token.MakeAuthURL() << std::endl ; - - std::cout - << "\n-----------------------\n" - << "Please input the authentication code here: " << std::endl ; - std::string code ; - std::cin >> code ; - + + std::string code = AuthCode(uri); token.Auth( code ) ; // save to config diff --git a/package/fedora16/grive.spec b/package/fedora16/grive.spec index 3a7e767..2f774d9 100644 --- a/package/fedora16/grive.spec +++ b/package/fedora16/grive.spec @@ -36,6 +36,7 @@ BuildRequires: expat-devel BuildRequires: openssl-devel BuildRequires: boost-devel BuildRequires: binutils-devel +BuildRequires: cpprest-devel %description The purpose of this project is to provide an independent implementation