pull/369/merge
Brian Clark 2022-09-10 13:25:57 -04:00 committed by GitHub
commit 06ba4eb4fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 143 additions and 31 deletions

View File

@ -1,3 +1,28 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Grive2 0.5.2-dev](#grive2-052-dev)
- [Usage](#usage)
- [Exclude specific files and folders from sync: .griveignore](#exclude-specific-files-and-folders-from-sync-griveignore)
- [Scheduled syncs and syncs on file change events](#scheduled-syncs-and-syncs-on-file-change-events)
- [Shared files](#shared-files)
- [Different OAuth2 client to workaround over quota and google approval issues](#different-oauth2-client-to-workaround-over-quota-and-google-approval-issues)
- [Installation](#installation)
- [Install dependencies](#install-dependencies)
- [Build Debian packages](#build-debian-packages)
- [Manual build](#manual-build)
- [Version History](#version-history)
- [Grive2 v0.5.2-dev](#grive2-v052-dev)
- [Grive2 v0.5.1](#grive2-v051)
- [Grive2 v0.5](#grive2-v05)
- [Grive2 v0.4.2](#grive2-v042)
- [Grive2 v0.4.1](#grive2-v041)
- [Grive2 v0.4.0](#grive2-v040)
- [Grive v0.3](#grive-v03)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Grive2 0.5.2-dev
13 Nov 2019, Vitaliy Filippov
@ -39,12 +64,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 +179,7 @@ You need the following libraries:
- libgcrypt
- Boost (Boost filesystem, program_options, regex, unit_test_framework and system are required)
- expat
- [libcpprest-dev](https://github.com/Microsoft/cpprestsdk)
There are also some optional dependencies:
- CppUnit (for unit tests)
@ -165,16 +191,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,6 +45,10 @@
#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 ;
@ -52,6 +56,9 @@ const std::string default_secret = APP_SECRET ;
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 +108,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 +179,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,8 +248,9 @@ int Main( int argc, char **argv )
std::string secret = vm.count( "secret" ) > 0
? vm["secret"].as<std::string>()
: default_secret ;
std::string redirect_uri = config.Get("redirect-uri").Str();
OAuth2 token( http.get(), id, secret ) ;
OAuth2 token( http.get(), id, secret, redirect_uri ) ;
if ( vm.count("print-url") )
{
@ -194,33 +260,31 @@ 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(redirect_uri);
token.Auth( code ) ;
// save to config
config.Set( "id", Val( id ) ) ;
config.Set( "secret", Val( secret ) ) ;
config.Set( "refresh_token", Val( token.RefreshToken() ) ) ;
config.Set( "redirect-uri", Val( redirect_uri ) ) ;
config.Save() ;
}
std::string refresh_token ;
std::string id ;
std::string secret ;
std::string redirect_uri ;
try
{
refresh_token = config.Get("refresh_token").Str() ;
id = config.Get("id").Str() ;
secret = config.Get("secret").Str() ;
redirect_uri = config.Get("redirect-uri").Str() ;
}
catch ( Exception& e )
{
@ -232,7 +296,7 @@ int Main( int argc, char **argv )
return -1;
}
OAuth2 token( http.get(), refresh_token, id, secret ) ;
OAuth2 token( http.get(), refresh_token, id, secret, redirect_uri ) ;
AuthAgent agent( token, http.get() ) ;
v2::Syncer2 syncer( &agent );

View File

@ -35,12 +35,14 @@ const std::string token_url = "https://accounts.google.com/o/oauth2/token" ;
OAuth2::OAuth2(
http::Agent* agent,
const std::string& refresh_code,
const std::string& client_id,
const std::string& client_secret ) :
const std::string& client_id,
const std::string& client_secret,
const std::string& redirect_uri ) :
m_refresh( refresh_code ),
m_agent( agent ),
m_client_id( client_id ),
m_client_secret( client_secret )
m_client_secret( client_secret ),
m_redirect_uri ( redirect_uri )
{
Refresh( ) ;
}
@ -48,10 +50,12 @@ OAuth2::OAuth2(
OAuth2::OAuth2(
http::Agent* agent,
const std::string& client_id,
const std::string& client_secret ) :
const std::string& client_secret,
const std::string& redirect_uri ) :
m_agent( agent ),
m_client_id( client_id ),
m_client_secret( client_secret )
m_client_secret( client_secret ),
m_redirect_uri( redirect_uri )
{
}
@ -61,7 +65,7 @@ void OAuth2::Auth( const std::string& auth_code )
"code=" + auth_code +
"&client_id=" + m_client_id +
"&client_secret=" + m_client_secret +
"&redirect_uri=" + "urn:ietf:wg:oauth:2.0:oob" +
"&redirect_uri=" + m_redirect_uri +
"&grant_type=authorization_code" ;
http::ValResponse resp ;
@ -85,7 +89,7 @@ std::string OAuth2::MakeAuthURL()
{
return "https://accounts.google.com/o/oauth2/auth"
"?scope=" + m_agent->Escape( "https://www.googleapis.com/auth/drive" ) +
"&redirect_uri=urn:ietf:wg:oauth:2.0:oob"
"&redirect_uri=" + m_redirect_uri +
"&response_type=code"
"&client_id=" + m_client_id ;
}

View File

@ -35,12 +35,14 @@ public :
OAuth2(
http::Agent* agent,
const std::string& client_id,
const std::string& client_secret ) ;
const std::string& client_secret,
const std::string& redirect_uri ) ;
OAuth2(
http::Agent* agent,
const std::string& refresh_code,
const std::string& client_id,
const std::string& client_secret ) ;
const std::string& client_secret,
const std::string& redirect_uri ) ;
std::string Str() const ;
@ -62,6 +64,7 @@ private :
const std::string m_client_id ;
const std::string m_client_secret ;
const std::string m_redirect_uri ;
} ;
} // end of namespace

View File

@ -32,9 +32,10 @@ namespace po = boost::program_options;
namespace gr {
const std::string default_filename = ".grive";
const char *env_name = "GR_CONFIG";
const std::string default_root_folder = ".";
const char *env_name = "GR_CONFIG";
const std::string default_filename = ".grive";
const std::string default_root_folder = ".";
const std::string default_redirect_uri = "http://localhost:9898" ;
Config::Config( const po::variables_map& vm )
{
@ -58,6 +59,14 @@ Config::Config( const po::variables_map& vm )
m_path = GetPath( fs::path(m_cmd["path"].Str()) ) ;
m_file = Read( ) ;
if ( vm.count( "redirect-uri" ) > 0 ) {
m_cmd.Add( "redirect-uri", Val( vm["redirect-uri"].as<std::string>() ) );
} else if (m_file.Has( "redirect-uri" )) {
;
} else {
m_cmd.Add( "redirect-uri", Val( default_redirect_uri ) );
}
}
fs::path Config::GetPath( const fs::path& root_path )
@ -84,7 +93,7 @@ void Config::Save( )
void Config::Set( const std::string& key, const Val& value )
{
m_file.Add( key, value ) ;
m_file.Set( key, value ) ;
}
Val Config::Get( const std::string& key ) const

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