Cookie: Added Support For Chromium Based Browser
Created 'cookie' class to handle cookies easier. The 'cookie' class contains a name, value, and length. The 'cookie' class also has functions for getting values for an sqlite database and decrypting chrome cookies.
This commit is contained in:
parent
1f0d1b8baf
commit
5c86f201cd
|
@ -22,7 +22,7 @@ sudo xbps-install -S libcurl sqlite-devel
|
||||||
sudo apt install libcurl4-gnutls-dev sqlite-devel
|
sudo apt install libcurl4-gnutls-dev sqlite-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
## cookies
|
## Cookies
|
||||||
### Firefox
|
### Firefox
|
||||||
#### Option 1 (requires sqlite-devel)
|
#### Option 1 (requires sqlite-devel)
|
||||||
Create a file named `firefox_profile` in the build directory and paste in your [firefox profile folder path](https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data)
|
Create a file named `firefox_profile` in the build directory and paste in your [firefox profile folder path](https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data)
|
||||||
|
@ -42,7 +42,7 @@ Create a file called `auth_cookie` and paste the cookie in the file \
|
||||||
Go back to firefox and copy the `_session` cookie into a file named `session_cookie` \
|
Go back to firefox and copy the `_session` cookie into a file named `session_cookie` \
|
||||||
This needs to be redone everytime the cookie expires (~30 minutes)
|
This needs to be redone everytime the cookie expires (~30 minutes)
|
||||||
### chrome
|
### chrome
|
||||||
#### Option 1 (requires sqlite-devel and libgcrypt) NOT CURRENTLY FUNCTIONAL
|
#### Option 1 (requires sqlite-devel and libgcrypt)
|
||||||
Create a file named `chrome_profile` in the build directory and paste in your chrome profile folder path (found on [chrome://version](chrome://version))
|
Create a file named `chrome_profile` in the build directory and paste in your chrome profile folder path (found on [chrome://version](chrome://version))
|
||||||
#### Option 2
|
#### Option 2
|
||||||
Go to settings > privacy and security > cookies > see all cookies > vhx.tv > __cf_bm \
|
Go to settings > privacy and security > cookies > see all cookies > vhx.tv > __cf_bm \
|
||||||
|
|
112
src/episode.cpp
112
src/episode.cpp
|
@ -399,6 +399,118 @@ namespace dropout_dl {
|
||||||
return config_page;
|
return config_page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cookie::get_value_from_db(sqlite3 *db, const std::string &sql_query_base, const std::string& value, bool verbose, int (*callback)(void*,int,char**,char**)) {
|
||||||
|
std::string sql_mod_base = sql_query_base;
|
||||||
|
|
||||||
|
if (sql_mod_base.find("WHERE") == std::string::npos) {
|
||||||
|
sql_mod_base += " WHERE ";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sql_mod_base += " AND ";
|
||||||
|
}
|
||||||
|
|
||||||
|
sql_mod_base += "name='" + this->name + "';";
|
||||||
|
|
||||||
|
std::string sql_value_query = "SELECT " + value + ' ' + sql_mod_base;
|
||||||
|
std::string sql_length_query = "SELECT length(" + value + ") " + sql_mod_base;
|
||||||
|
std::string tmp;
|
||||||
|
char *err_code = nullptr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << sql_value_query << '\n' << sql_length_query << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sqlite3_exec(db, sql_length_query.c_str(), callback, &tmp, &err_code);
|
||||||
|
|
||||||
|
if (rc != SQLITE_OK) {
|
||||||
|
fprintf(stderr, "SQL error: %s\n", err_code);
|
||||||
|
sqlite3_free(err_code);
|
||||||
|
sqlite3_close(db);
|
||||||
|
exit(3);
|
||||||
|
} else if (verbose) {
|
||||||
|
std::cout << "Got " << this->name << " cookie length\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->len = std::stoi(tmp);
|
||||||
|
|
||||||
|
rc = sqlite3_exec(db, sql_value_query.c_str(), callback, &tmp, &err_code);
|
||||||
|
|
||||||
|
if (rc != SQLITE_OK) {
|
||||||
|
fprintf(stderr, "SQL error: %s\n", err_code);
|
||||||
|
sqlite3_free(err_code);
|
||||||
|
sqlite3_close(db);
|
||||||
|
exit(3);
|
||||||
|
} else if (verbose) {
|
||||||
|
std::cout << "Got " << this->name << " cookie\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->str = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cookie::format_from_chrome() {
|
||||||
|
this->str = this->str.substr(3);
|
||||||
|
this->len -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cookie::chrome_decrypt(const std::string &password, int iterations, const std::string &salt, int length) {
|
||||||
|
|
||||||
|
this->format_from_chrome();
|
||||||
|
|
||||||
|
uint8_t key[32];
|
||||||
|
|
||||||
|
char output[this->len + 2];
|
||||||
|
|
||||||
|
char iv[16];
|
||||||
|
|
||||||
|
for (char& c : iv) {
|
||||||
|
c = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (char& c : output) {
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcry_kdf_derive(password.c_str(), password.size(), GCRY_KDF_PBKDF2, GCRY_KDF_ARGON2ID, salt.c_str(), salt.size(), iterations, length, key);
|
||||||
|
|
||||||
|
gcry_cipher_hd_t handle;
|
||||||
|
|
||||||
|
gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
|
||||||
|
|
||||||
|
gcry_cipher_setkey(handle, (const void*) &key, length);
|
||||||
|
|
||||||
|
gcry_cipher_setiv(handle, (const void*)&iv, 16);
|
||||||
|
|
||||||
|
unsigned long err = gcry_cipher_decrypt(handle, output, this->len, this->str.c_str(), this->len);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
std::cout << gcry_strerror(err) << std::endl;
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this->str = output;
|
||||||
|
this->str = this->str.substr(0, this->len-7);
|
||||||
|
this->len -= 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cookie::url_decode() {
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
for (int i = 0; i < this->str.size() - 3; i++) {
|
||||||
|
if (substr_is(this->str, i, "%3D")) {
|
||||||
|
out += "=";
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out += this->str[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->str = out;
|
||||||
|
this->len = out.size();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> episode::get_qualities() {
|
std::vector<std::string> episode::get_qualities() {
|
||||||
if (!qualities.empty()) {
|
if (!qualities.empty()) {
|
||||||
return qualities;
|
return qualities;
|
||||||
|
|
101
src/episode.h
101
src/episode.h
|
@ -9,9 +9,104 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#ifdef DROPOUT_DL_GCRYPT
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace dropout_dl {
|
namespace dropout_dl {
|
||||||
|
|
||||||
|
class cookie {
|
||||||
|
public:
|
||||||
|
static int sqlite_write_callback(void* data, int argc, char** argv, char** azColName)
|
||||||
|
{
|
||||||
|
if (argc < 1) {
|
||||||
|
std::cerr << "ERROR: sqlite could not find dropout.tv cookie" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*(std::string*)data = argv[0];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sqlite_write_callback_uchar(void* data, int argc, char** argv, char** azColName)
|
||||||
|
{
|
||||||
|
if (argc < 1) {
|
||||||
|
std::cerr << "ERROR: sqlite could not find dropout.tv cookie" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
auto* ck = (dropout_dl::cookie*)data;
|
||||||
|
|
||||||
|
for (int i = 0; i < ck->len; i++) {
|
||||||
|
if (argv[0][i] > 32 && argv[0][i] < 126) {
|
||||||
|
std::cout << (unsigned char) argv[0][i] << ' ';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << std::hex << ((int)argv[0][i] & 0xFF) << ' ';
|
||||||
|
}
|
||||||
|
ck->str[i] = (unsigned char)argv[0][i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string str;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
|
||||||
|
explicit cookie(const std::string& name) {
|
||||||
|
this->name = name;
|
||||||
|
this->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie(const std::string& name, const std::string& cookie) {
|
||||||
|
this->name = name;
|
||||||
|
this->str = cookie;
|
||||||
|
this->len = cookie.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie(const std::string& cookie, int length) {
|
||||||
|
this->str = cookie;
|
||||||
|
this->name = "?";
|
||||||
|
this->len = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie(const std::string& name, const std::string& cookie, int length) {
|
||||||
|
this->name = name;
|
||||||
|
this->str = cookie;
|
||||||
|
this->len = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param db - An sqlite3 database
|
||||||
|
* @param sql_query_base - A base without the name search e.g. "FROM cookies" this function would then append the text "SELECT <value>" and "WHERE name='<name>'"
|
||||||
|
* @param value - The name of the value to fill the cookie with
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void get_value_from_db(sqlite3* db, const std::string& sql_query_base, const std::string& value, bool verbose = false, int (*callback)(void*,int,char**,char**) = sqlite_write_callback);
|
||||||
|
|
||||||
|
void format_from_chrome();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param password - Default is "peanuts". This works for linux. The password should be keychain password on MacOS
|
||||||
|
* @param salt - Salt is "saltysalt" for both MacOS and Linux
|
||||||
|
* @param length - Length of 16 is standard for both MacOS and Linux
|
||||||
|
* @param iterations - 1 on linux and 1003 on MacOS
|
||||||
|
*/
|
||||||
|
void chrome_decrypt(const std::string& password = "peanuts", int iterations = 1, const std::string& salt = "saltysalt", int length = 16);
|
||||||
|
|
||||||
|
void url_decode();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
bool substr_is(const std::string& string, int start, const std::string& test_str);
|
bool substr_is(const std::string& string, int start, const std::string& test_str);
|
||||||
|
|
||||||
void replace_all(std::string& str, const std::string& from, const std::string& to);
|
void replace_all(std::string& str, const std::string& from, const std::string& to);
|
||||||
|
@ -76,12 +171,12 @@ namespace dropout_dl {
|
||||||
|
|
||||||
void download(const std::string& quality, const std::string& series_directory, std::string filename = "");
|
void download(const std::string& quality, const std::string& series_directory, std::string filename = "");
|
||||||
|
|
||||||
episode(const std::string& episode_url, std::vector<std::string> cookies, bool verbose = false) {
|
episode(const std::string& episode_url, std::vector<cookie> cookies, bool verbose = false) {
|
||||||
|
|
||||||
this->episode_url = episode_url;
|
this->episode_url = episode_url;
|
||||||
this->verbose = verbose;
|
this->verbose = verbose;
|
||||||
|
|
||||||
episode_data = get_episode_page(episode_url, cookies[0], cookies[1]);
|
episode_data = get_episode_page(episode_url, cookies[0].str, cookies[1].str);
|
||||||
|
|
||||||
name = get_episode_name(episode_data);
|
name = get_episode_name(episode_data);
|
||||||
|
|
||||||
|
@ -124,7 +219,7 @@ namespace dropout_dl {
|
||||||
std::cout << "Got embedded url: " << this->embedded_url << '\n';
|
std::cout << "Got embedded url: " << this->embedded_url << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
this->embedded_page_data = get_embedded_page(this->embedded_url, cookies[0]);
|
this->embedded_page_data = get_embedded_page(this->embedded_url, cookies[0].str);
|
||||||
|
|
||||||
if (this->embedded_page_data.find("you are not authorized") != std::string::npos) {
|
if (this->embedded_page_data.find("you are not authorized") != std::string::npos) {
|
||||||
std::cerr << "ERROR: Could not access video. Try refreshing cookies.\n";
|
std::cerr << "ERROR: Could not access video. Try refreshing cookies.\n";
|
||||||
|
|
481
src/main.cpp
481
src/main.cpp
|
@ -4,296 +4,12 @@
|
||||||
|
|
||||||
#ifdef DROPOUT_DL_SQLITE
|
#ifdef DROPOUT_DL_SQLITE
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
#ifdef DROPOUT_DL_GCRYPT
|
|
||||||
#include <gcrypt.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int sqlite_write_callback(void* data, int argc, char** argv, char** azColName)
|
namespace dropout_dl {
|
||||||
{
|
|
||||||
if (argc < 1) {
|
|
||||||
std::cerr << "ERROR: sqlite could not find dropout.tv cookie" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*(std::string*)data = argv[0];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DROPOUT_DL_SQLITE
|
class options {
|
||||||
std::vector<std::string> get_cookies_from_firefox(const std::filesystem::path& firefox_profile_path, bool verbose = false) {
|
public:
|
||||||
|
|
||||||
std::fstream firefox_profile_file(firefox_profile_path);
|
|
||||||
std::string firefox_profile;
|
|
||||||
|
|
||||||
std::string auth_cookie;
|
|
||||||
std::string session_cookie;
|
|
||||||
|
|
||||||
std::vector<std::string> out;
|
|
||||||
|
|
||||||
firefox_profile_file >> firefox_profile;
|
|
||||||
|
|
||||||
if (std::filesystem::is_directory(firefox_profile)) {
|
|
||||||
|
|
||||||
sqlite3 *db;
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
std::cout << "Getting firefox cookies from firefox sqlite db\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!std::filesystem::is_directory("tmp"))
|
|
||||||
std::filesystem::create_directories("tmp");
|
|
||||||
std::filesystem::remove("tmp/firefox_cookies.sqlite");
|
|
||||||
std::filesystem::copy_file(firefox_profile + "/cookies.sqlite", "tmp/firefox_cookies.sqlite");
|
|
||||||
|
|
||||||
int rc = sqlite3_open("tmp/firefox_cookies.sqlite", &db);
|
|
||||||
if (rc) {
|
|
||||||
std::cerr << "Can't open database: " << sqlite3_errmsg(db) << '\n';
|
|
||||||
exit(1);
|
|
||||||
} else {
|
|
||||||
if (verbose) {
|
|
||||||
std::cout << "Firefox database opened successfully\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *err_code = nullptr;
|
|
||||||
|
|
||||||
std::string sql("SELECT value FROM moz_cookies WHERE host LIKE '%dropout.tv%' AND name='__cf_bm';");
|
|
||||||
|
|
||||||
rc = sqlite3_exec(db, sql.c_str(), sqlite_write_callback, &auth_cookie, &err_code);
|
|
||||||
|
|
||||||
out.emplace_back(auth_cookie);
|
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
|
||||||
fprintf(stderr, "SQL error: %s\n", err_code);
|
|
||||||
sqlite3_free(err_code);
|
|
||||||
sqlite3_close(db);
|
|
||||||
exit(2);
|
|
||||||
} else if (verbose) {
|
|
||||||
std::cout << "Got __cf_bm cookie from firefox sqlite db\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
sql = "SELECT value FROM moz_cookies WHERE host LIKE '%dropout.tv%' AND name='_session';";
|
|
||||||
|
|
||||||
rc = sqlite3_exec(db, sql.c_str(), sqlite_write_callback, &session_cookie, &err_code);
|
|
||||||
|
|
||||||
out.emplace_back(session_cookie);
|
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
|
||||||
fprintf(stderr, "SQL error: %s\n", err_code);
|
|
||||||
sqlite3_free(err_code);
|
|
||||||
sqlite3_close(db);
|
|
||||||
exit(3);
|
|
||||||
} else if (verbose) {
|
|
||||||
std::cout << "Got _session cookie from firefox sqlite db\n";
|
|
||||||
}
|
|
||||||
sqlite3_close(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DROPOUT_DL_GCRYPT
|
|
||||||
std::vector<std::string> get_cookies_from_chrome(const std::filesystem::path& chrome_profile_path, bool verbose = false) {
|
|
||||||
|
|
||||||
std::fstream chrome_profile_file(chrome_profile_path);
|
|
||||||
std::string chrome_profile;
|
|
||||||
|
|
||||||
std::string auth_cookie;
|
|
||||||
int auth_cookie_length;
|
|
||||||
std::string session_cookie;
|
|
||||||
int session_cookie_length;
|
|
||||||
|
|
||||||
std::vector<std::string> out;
|
|
||||||
|
|
||||||
getline(chrome_profile_file, chrome_profile);
|
|
||||||
|
|
||||||
if (std::filesystem::is_directory(chrome_profile)) {
|
|
||||||
|
|
||||||
sqlite3 *db;
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
std::cout << "Getting chrome cookies from chrome sqlite db\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
int rc = sqlite3_open((chrome_profile + "/Cookies").c_str(), &db);
|
|
||||||
if (rc) {
|
|
||||||
std::cerr << "Can't open database: " << sqlite3_errmsg(db) << '\n';
|
|
||||||
exit(1);
|
|
||||||
} else {
|
|
||||||
if (verbose) {
|
|
||||||
std::cout << "Chrome database opened successfully\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *err_code = nullptr;
|
|
||||||
|
|
||||||
std::string len;
|
|
||||||
|
|
||||||
std::string sql = "SELECT length(encrypted_value) FROM cookies WHERE host_key LIKE '%dropout.tv%' AND name='__cf_bm';";
|
|
||||||
|
|
||||||
sqlite3_exec(db, sql.c_str(), sqlite_write_callback, &len, &err_code);
|
|
||||||
|
|
||||||
auth_cookie_length = std::stoi(len);
|
|
||||||
|
|
||||||
sql = "SELECT encrypted_value FROM cookies WHERE host_key LIKE '%dropout.tv%' AND name='__cf_bm';";
|
|
||||||
|
|
||||||
rc = sqlite3_exec(db, sql.c_str(), sqlite_write_callback, &auth_cookie, &err_code);
|
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
|
||||||
fprintf(stderr, "SQL error: %s\n", err_code);
|
|
||||||
sqlite3_free(err_code);
|
|
||||||
sqlite3_close(db);
|
|
||||||
exit(2);
|
|
||||||
} else if (verbose) {
|
|
||||||
std::cout << "Got __cf_bm cookie from chrome sqlite db\n" << auth_cookie << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
sql = "SELECT length(encrypted_value) FROM cookies WHERE host_key LIKE '%dropout.tv%' AND name='_session';";
|
|
||||||
|
|
||||||
sqlite3_exec(db, sql.c_str(), sqlite_write_callback, &len, &err_code);
|
|
||||||
|
|
||||||
session_cookie_length = std::stoi(len);
|
|
||||||
|
|
||||||
sql = "SELECT encrypted_value FROM cookies WHERE host_key LIKE '%dropout.tv%' AND name='_session';";
|
|
||||||
|
|
||||||
rc = sqlite3_exec(db, sql.c_str(), sqlite_write_callback, &session_cookie, &err_code);
|
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
|
||||||
fprintf(stderr, "SQL error: %s\n", err_code);
|
|
||||||
sqlite3_free(err_code);
|
|
||||||
sqlite3_close(db);
|
|
||||||
exit(3);
|
|
||||||
} else if (verbose) {
|
|
||||||
std::cout << "Got _session cookie from chrome sqlite db\n";
|
|
||||||
}
|
|
||||||
sqlite3_close(db);
|
|
||||||
|
|
||||||
// system(("echo \"SELECT value FROM moz_cookies WHERE originAttributes LIKE '%dropout.tv%';\" | sqlite3 " + firefox_profile + "/cookies.sqlite > cookie").c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// For mac os this is your keychain password
|
|
||||||
// For linux leave as "peanuts"
|
|
||||||
std::string password = "peanuts";
|
|
||||||
std::string salt = "saltysalt";
|
|
||||||
int length = 16;
|
|
||||||
int iterations = 1;
|
|
||||||
|
|
||||||
uint8_t key[32];
|
|
||||||
|
|
||||||
char output[2048];
|
|
||||||
|
|
||||||
char iv[16];
|
|
||||||
|
|
||||||
for (char& c : iv) {
|
|
||||||
c = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (char& c : output) {
|
|
||||||
c = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < auth_cookie_length; i++) {
|
|
||||||
std::cout << std::hex << (0xFF & (int)auth_cookie[i]) << ' ';
|
|
||||||
}
|
|
||||||
std::cout << '\n';
|
|
||||||
|
|
||||||
gcry_kdf_derive(password.c_str(), password.size(), GCRY_KDF_PBKDF2, GCRY_KDF_ARGON2ID, salt.c_str(), salt.size(), iterations, length, key);
|
|
||||||
|
|
||||||
gcry_cipher_hd_t handle;
|
|
||||||
|
|
||||||
gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
|
|
||||||
|
|
||||||
gcry_cipher_setkey(handle, (const void*) &key, length);
|
|
||||||
|
|
||||||
gcry_cipher_setiv(handle, (const void*)&iv, 16);
|
|
||||||
|
|
||||||
unsigned long err = gcry_cipher_decrypt(handle, (unsigned char*)output, 2048, auth_cookie.c_str() + 3, auth_cookie_length - 3);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
std::cout << gcry_strerror(err) << std::endl;
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (char& c : output) {
|
|
||||||
if (c == '\017') {
|
|
||||||
c = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out.emplace_back(output);
|
|
||||||
|
|
||||||
gcry_cipher_setiv(handle, (const void*)&iv, 16);
|
|
||||||
|
|
||||||
gcry_cipher_decrypt(handle, (unsigned char*)output, 2048, session_cookie.c_str() + 3, session_cookie_length - 3);
|
|
||||||
|
|
||||||
out.emplace_back(output);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::vector<std::string> get_cookies_from_files(const std::filesystem::path& auth_cookie_path, const std::filesystem::path& session_cookie_path, bool verbose = false) {
|
|
||||||
std::fstream auth_cookie_file("auth_cookie");
|
|
||||||
std::fstream session_cookie_file("session_cookie");
|
|
||||||
|
|
||||||
std::string auth_cookie;
|
|
||||||
std::string session_cookie;
|
|
||||||
|
|
||||||
std::vector<std::string> out;
|
|
||||||
|
|
||||||
auth_cookie_file >> auth_cookie;
|
|
||||||
if (verbose) {
|
|
||||||
std::cout << "Got __cf_bm cookie from auth_cookie file db\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
out.emplace_back(auth_cookie);
|
|
||||||
|
|
||||||
session_cookie_file >> session_cookie;
|
|
||||||
if (verbose) {
|
|
||||||
std::cout << "Got _session cookie from auth_cookie file db\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
out.emplace_back(session_cookie);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> get_cookies(bool verbose = false) {
|
|
||||||
|
|
||||||
#ifdef DROPOUT_DL_SQLITE
|
|
||||||
std::filesystem::path firefox_profile("firefox_profile");
|
|
||||||
#ifdef DROPOUT_DL_GCRYPT
|
|
||||||
std::filesystem::path chrome_profile("chrome_profile");
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
std::filesystem::path auth_cookie("auth_cookie");
|
|
||||||
std::filesystem::path session_cookie("session_cookie");
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DROPOUT_DL_SQLITE
|
|
||||||
if (std::filesystem::exists(firefox_profile)) {
|
|
||||||
return get_cookies_from_firefox(firefox_profile, verbose);
|
|
||||||
} else
|
|
||||||
#ifdef DROPOUT_DL_GCRYPT
|
|
||||||
if (std::filesystem::exists(chrome_profile)) {
|
|
||||||
return get_cookies_from_chrome(chrome_profile, verbose);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
if (std::filesystem::exists(auth_cookie) && std::filesystem::exists(session_cookie)){
|
|
||||||
return get_cookies_from_files(auth_cookie, session_cookie, verbose);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::cerr << "ERROR: dropout.tv cookies could not be found" << std::endl;
|
|
||||||
exit(7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class options {
|
|
||||||
public:
|
|
||||||
|
|
||||||
std::string url;
|
std::string url;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
|
@ -304,7 +20,7 @@ public:
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string output_directory;
|
std::string output_directory;
|
||||||
std::string episode;
|
std::string episode;
|
||||||
std::vector<std::string> cookies;
|
std::vector<cookie> cookies;
|
||||||
|
|
||||||
static std::vector<std::string> convert_program_args(int argc, char** argv) {
|
static std::vector<std::string> convert_program_args(int argc, char** argv) {
|
||||||
std::vector<std::string> out;
|
std::vector<std::string> out;
|
||||||
|
@ -370,7 +86,7 @@ public:
|
||||||
"\t--help Display this message\n"
|
"\t--help Display this message\n"
|
||||||
"\t--quality Set the quality of the downloaded video. Quality can be set to 'all' which\n"
|
"\t--quality Set the quality of the downloaded video. Quality can be set to 'all' which\n"
|
||||||
"\t will download all qualities and place them into separate folders\n"
|
"\t will download all qualities and place them into separate folders\n"
|
||||||
"\t--output Set the output filename\n"
|
"\t--output Set the output filename. Only works for single episode downloads\n"
|
||||||
"\t--output-directory Set the directory where files are output\n"
|
"\t--output-directory Set the directory where files are output\n"
|
||||||
"\t--verbose Display debug information while running\n"
|
"\t--verbose Display debug information while running\n"
|
||||||
"\t--force-cookies Interpret the next to arguments as authentication cookie and session cookie\n"
|
"\t--force-cookies Interpret the next to arguments as authentication cookie and session cookie\n"
|
||||||
|
@ -393,15 +109,192 @@ public:
|
||||||
quality = "1080p";
|
quality = "1080p";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DROPOUT_DL_SQLITE
|
||||||
|
std::vector<dropout_dl::cookie> get_cookies_from_firefox(const std::filesystem::path& firefox_profile_path, bool verbose = false) {
|
||||||
|
|
||||||
|
std::fstream firefox_profile_file(firefox_profile_path);
|
||||||
|
std::string firefox_profile;
|
||||||
|
|
||||||
|
dropout_dl::cookie auth("__cf_bm");
|
||||||
|
dropout_dl::cookie session("_session");
|
||||||
|
|
||||||
|
std::vector<dropout_dl::cookie> out;
|
||||||
|
|
||||||
|
firefox_profile_file >> firefox_profile;
|
||||||
|
|
||||||
|
if (std::filesystem::is_directory(firefox_profile)) {
|
||||||
|
|
||||||
|
sqlite3 *db;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Getting firefox cookies from firefox sqlite db\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::filesystem::is_directory("tmp"))
|
||||||
|
std::filesystem::create_directories("tmp");
|
||||||
|
std::filesystem::remove("tmp/firefox_cookies.sqlite");
|
||||||
|
std::filesystem::copy_file(firefox_profile + "/cookies.sqlite", "tmp/firefox_cookies.sqlite");
|
||||||
|
|
||||||
|
int rc = sqlite3_open("tmp/firefox_cookies.sqlite", &db);
|
||||||
|
if (rc) {
|
||||||
|
std::cerr << "Can't open database: " << sqlite3_errmsg(db) << '\n';
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Firefox database opened successfully\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string len;
|
||||||
|
|
||||||
|
auth.get_value_from_db(db, "FROM moz_cookies WHERE host LIKE '%dropout.tv%'", "value");
|
||||||
|
|
||||||
|
session.get_value_from_db(db, "FROM moz_cookies WHERE host LIKE '%dropout.tv%'", "value");
|
||||||
|
|
||||||
|
sqlite3_close(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << auth.name << ": " << auth.len << ": " << auth.str << '\n';
|
||||||
|
|
||||||
|
std::cout << session.name << ": " << session.len << ": " << session.str << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push_back(auth);
|
||||||
|
out.push_back(session);
|
||||||
|
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DROPOUT_DL_GCRYPT
|
||||||
|
std::vector<dropout_dl::cookie> get_cookies_from_chrome(const std::filesystem::path& chrome_profile_path, bool verbose = false) {
|
||||||
|
|
||||||
|
std::fstream chrome_profile_file(chrome_profile_path);
|
||||||
|
std::string chrome_profile;
|
||||||
|
|
||||||
|
dropout_dl::cookie auth("__cf_bm");
|
||||||
|
dropout_dl::cookie session("_session");
|
||||||
|
|
||||||
|
std::vector<dropout_dl::cookie> out;
|
||||||
|
|
||||||
|
getline(chrome_profile_file, chrome_profile);
|
||||||
|
|
||||||
|
if (std::filesystem::is_directory(chrome_profile)) {
|
||||||
|
|
||||||
|
sqlite3 *db;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Getting chrome cookies from chrome sqlite db\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = sqlite3_open((chrome_profile + "/Cookies").c_str(), &db);
|
||||||
|
if (rc) {
|
||||||
|
std::cerr << "Can't open database: " << sqlite3_errmsg(db) << '\n';
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Chrome database opened successfully\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string len;
|
||||||
|
|
||||||
|
auth.get_value_from_db(db, "FROM cookies WHERE host_key LIKE '%dropout.tv%'", "encrypted_value");
|
||||||
|
|
||||||
|
session.get_value_from_db(db, "FROM cookies WHERE host_key LIKE '%dropout.tv%'", "encrypted_value");
|
||||||
|
|
||||||
|
sqlite3_close(db);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auth.chrome_decrypt();
|
||||||
|
|
||||||
|
session.chrome_decrypt();
|
||||||
|
|
||||||
|
session.url_decode();
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << auth.name << ": " << auth.len << ": " << auth.str << '\n';
|
||||||
|
|
||||||
|
std::cout << session.name << ": " << session.len << ": " << session.str << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push_back(auth);
|
||||||
|
out.push_back(session);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::vector<dropout_dl::cookie> get_cookies_from_files(const std::filesystem::path& auth_cookie_path, const std::filesystem::path& session_cookie_path, bool verbose = false) {
|
||||||
|
std::fstream auth_cookie_file("auth_cookie");
|
||||||
|
std::fstream session_cookie_file("session_cookie");
|
||||||
|
|
||||||
|
std::string auth_cookie;
|
||||||
|
std::string session_cookie;
|
||||||
|
|
||||||
|
std::vector<dropout_dl::cookie> out;
|
||||||
|
|
||||||
|
auth_cookie_file >> auth_cookie;
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Got __cf_bm cookie from auth_cookie file db\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
out.emplace_back(auth_cookie);
|
||||||
|
|
||||||
|
session_cookie_file >> session_cookie;
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Got _session cookie from auth_cookie file db\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
out.emplace_back(session_cookie);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<dropout_dl::cookie> get_cookies(bool verbose = false) {
|
||||||
|
|
||||||
|
#ifdef DROPOUT_DL_SQLITE
|
||||||
|
std::filesystem::path firefox_profile("firefox_profile");
|
||||||
|
#ifdef DROPOUT_DL_GCRYPT
|
||||||
|
std::filesystem::path chrome_profile("chrome_profile");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
std::filesystem::path auth_cookie("auth_cookie");
|
||||||
|
std::filesystem::path session_cookie("session_cookie");
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DROPOUT_DL_SQLITE
|
||||||
|
if (std::filesystem::exists(firefox_profile)) {
|
||||||
|
return get_cookies_from_firefox(firefox_profile, verbose);
|
||||||
|
} else
|
||||||
|
#ifdef DROPOUT_DL_GCRYPT
|
||||||
|
if (std::filesystem::exists(chrome_profile)) {
|
||||||
|
return get_cookies_from_chrome(chrome_profile, verbose);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
if (std::filesystem::exists(auth_cookie) && std::filesystem::exists(session_cookie)){
|
||||||
|
return get_cookies_from_files(auth_cookie, session_cookie, verbose);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cerr << "ERROR: dropout.tv cookies could not be found" << std::endl;
|
||||||
|
exit(7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
options options(argc, argv);
|
dropout_dl::options options(argc, argv);
|
||||||
|
|
||||||
std::cout << "quality: " << options.quality << std::endl;
|
// std::cout << "quality: " << options.quality << std::endl;
|
||||||
std::cout << "verbose: " << options.verbose << std::endl;
|
// std::cout << "verbose: " << options.verbose << std::endl;
|
||||||
std::cout << "url: \"" << options.url << '"' << std::endl;
|
// std::cout << "url: \"" << options.url << '"' << std::endl;
|
||||||
|
|
||||||
std::string firefox_profile;
|
std::string firefox_profile;
|
||||||
std::string chrome_profile;
|
std::string chrome_profile;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "season.h"
|
#include "season.h"
|
||||||
|
|
||||||
namespace dropout_dl {
|
namespace dropout_dl {
|
||||||
episode get_episode(const std::string& html_data, int& start_point, const std::vector<std::string>& cookies) {
|
episode get_episode(const std::string& html_data, int& start_point, const std::vector<cookie>& cookies) {
|
||||||
int link_start = 0;
|
int link_start = 0;
|
||||||
for (int i = start_point; i > 0; i--) {
|
for (int i = start_point; i > 0; i--) {
|
||||||
if (substr_is(html_data, i, "<a")) {
|
if (substr_is(html_data, i, "<a")) {
|
||||||
|
@ -33,7 +33,7 @@ namespace dropout_dl {
|
||||||
exit(8);
|
exit(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<episode> season::get_episodes(const std::string &html_data, const std::vector<std::string>& cookies) {
|
std::vector<episode> season::get_episodes(const std::string &html_data, const std::vector<cookie>& cookies) {
|
||||||
std::vector<episode> out;
|
std::vector<episode> out;
|
||||||
|
|
||||||
std::string site_video(R"(class="browse-item-link" data-track-event="site_video")");
|
std::string site_video(R"(class="browse-item-link" data-track-event="site_video")");
|
||||||
|
|
|
@ -18,11 +18,11 @@ namespace dropout_dl {
|
||||||
std::string page_data;
|
std::string page_data;
|
||||||
std::vector<episode> episodes;
|
std::vector<episode> episodes;
|
||||||
|
|
||||||
static std::vector<episode> get_episodes(const std::string& html_data, const std::vector<std::string>& cookies);
|
static std::vector<episode> get_episodes(const std::string& html_data, const std::vector<cookie>& cookies);
|
||||||
|
|
||||||
void download(const std::string& quality, const std::string& series_directory);
|
void download(const std::string& quality, const std::string& series_directory);
|
||||||
|
|
||||||
season(const std::string& url, const std::string& name, const std::vector<std::string>& cookies, const std::string& series_name = "") {
|
season(const std::string& url, const std::string& name, const std::vector<cookie>& cookies, const std::string& series_name = "") {
|
||||||
this->url = url;
|
this->url = url;
|
||||||
this->name = name;
|
this->name = name;
|
||||||
this->series_name = series_name;
|
this->series_name = series_name;
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace dropout_dl {
|
||||||
return "-1";
|
return "-1";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<season> series::get_seasons(const std::string &html_data, const std::vector<std::string>& cookies) {
|
std::vector<season> series::get_seasons(const std::string &html_data, const std::vector<cookie>& cookies) {
|
||||||
std::vector<season> out;
|
std::vector<season> out;
|
||||||
|
|
||||||
std::string search_class("js-switch-season");
|
std::string search_class("js-switch-season");
|
||||||
|
@ -127,7 +127,7 @@ namespace dropout_dl {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
season series::get_season(const std::string &url, const std::vector<std::string>& cookies) {
|
season series::get_season(const std::string &url, const std::vector<cookie>& cookies) {
|
||||||
std::string html_data = get_generic_page(url);
|
std::string html_data = get_generic_page(url);
|
||||||
|
|
||||||
std::string search_class("js-switch-season");
|
std::string search_class("js-switch-season");
|
||||||
|
|
|
@ -20,13 +20,13 @@ namespace dropout_dl {
|
||||||
|
|
||||||
static std::string get_series_name(const std::string& html_data);
|
static std::string get_series_name(const std::string& html_data);
|
||||||
|
|
||||||
static std::vector<season> get_seasons(const std::string& html_data, const std::vector<std::string>& cookies);
|
static std::vector<season> get_seasons(const std::string& html_data, const std::vector<cookie>& cookies);
|
||||||
|
|
||||||
static season get_season(const std::string& url, const std::vector<std::string>& cookies);
|
static season get_season(const std::string& url, const std::vector<cookie>& cookies);
|
||||||
|
|
||||||
void download(const std::string& quality, const std::string& base);
|
void download(const std::string& quality, const std::string& base);
|
||||||
|
|
||||||
explicit series(const std::string& url, const std::vector<std::string>& cookies) {
|
explicit series(const std::string& url, const std::vector<dropout_dl::cookie>& cookies) {
|
||||||
this->url = url;
|
this->url = url;
|
||||||
this->page_data = get_generic_page(url);
|
this->page_data = get_generic_page(url);
|
||||||
this->name = get_series_name(page_data);
|
this->name = get_series_name(page_data);
|
||||||
|
|
Loading…
Reference in New Issue