mirror of https://github.com/vitalif/grive2
Merge 58a183c876
into 6901fbb169
commit
06ba4eb4fd
41
README.md
41
README.md
|
@ -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,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
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 ;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue