Implement Google installed app loopback redirect OAuth flow

pull/369/head
Brian Clark 2022-08-28 10:38:57 -04:00 committed by Brian
parent 6901fbb169
commit 8bfa97c709
5 changed files with 87 additions and 16 deletions

View File

@ -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

2
debian/control vendored
View File

@ -2,7 +2,7 @@ Source: grive2
Section: net
Priority: optional
Maintainer: Vitaliy Filippov <vitalif@mail.ru>
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

View File

@ -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")

View File

@ -45,13 +45,21 @@
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <future>
#include <cpprest/http_listener.h>
#include <cpprest/uri.h>
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<std::string> 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<std::string>(), "Authentication secret")
( "print-url", "Only print url for request")
( "path,p", po::value<std::string>(), "Path to working copy root")
( "redirect-uri", po::value<std::string>(), "local URI on which to listen for auth redirect")
( "dir,s", po::value<std::string>(), "Single subdirectory to sync")
( "verbose,V", "Verbose mode. Enable more messages than normal.")
( "log-http", po::value<std::string>(), "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<std::string>()
: default_secret ;
std::string uri = vm.count( "redirect-uri" ) > 0
? vm["redirect-uri"].as<std::string>()
: 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

View File

@ -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