about summary refs log tree commit diff
path: root/pkgs/games/humblebundle/fetch-humble-bundle/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/games/humblebundle/fetch-humble-bundle/default.nix')
-rw-r--r--pkgs/games/humblebundle/fetch-humble-bundle/default.nix98
1 files changed, 96 insertions, 2 deletions
diff --git a/pkgs/games/humblebundle/fetch-humble-bundle/default.nix b/pkgs/games/humblebundle/fetch-humble-bundle/default.nix
index a27138d8..1249b56e 100644
--- a/pkgs/games/humblebundle/fetch-humble-bundle/default.nix
+++ b/pkgs/games/humblebundle/fetch-humble-bundle/default.nix
@@ -1,12 +1,83 @@
 { stdenv, curl, cacert, writeText, fetchFromGitHub, fetchpatch
 , python, pythonPackages
 
+# Dependencies for the captcha solver
+, pkgconfig, qt5, runCommandCC
+
 , email, password
 }:
 
 { name ? null, machineName, downloadName ? "Download", suffix ? "humblebundle", md5 }: let
   cafile = "${cacert}/etc/ssl/certs/ca-bundle.crt";
 
+  getCaptcha = let
+    injectedJS = ''
+      function waitForResponse() {
+        var response = captcha.get_response();
+        if (response != "")
+          document.title = response;
+        else
+          setTimeout(waitForResponse, 50);
+      }
+
+      waitForResponse();
+    '';
+
+    escapeCString = stdenv.lib.replaceStrings ["\"" "\n"] ["\\\"" "\\n"];
+
+    application = writeText "captcha.cc" ''
+      #include <QApplication>
+      #include <QWebEngineView>
+      #include <QTcpServer>
+
+      int main(int argc, char **argv) {
+        QApplication *app = new QApplication(argc, argv);
+        QTcpServer *server = new QTcpServer();
+        QWebEngineView *browser = new QWebEngineView();
+
+        if (!server->listen(QHostAddress::LocalHost, 18123)) {
+          qCritical() << "Unable to listen on port 18123!";
+          return 1;
+        }
+
+        qInfo() << "Waiting for connection from the HB downloader...";
+        if (!server->waitForNewConnection(-1)) {
+          qCritical() << "Unable to accept the connection!";
+          return 1;
+        }
+        qInfo() << "Connection established, spawning window to solve captcha.";
+
+        QTcpSocket *sock = server->nextPendingConnection();
+
+        browser->load(QUrl("https://www.humblebundle.com/user/captcha"));
+        browser->show();
+
+        browser->connect(browser, &QWebEngineView::loadFinished, [=]() {
+          browser->page()->runJavaScript("${escapeCString injectedJS}");
+          browser->connect(
+            browser, &QWebEngineView::titleChanged, [=](const QString &title) {
+              sock->write(title.toUtf8());
+              sock->flush();
+              sock->waitForBytesWritten();
+              sock->close();
+              server->close();
+              app->quit();
+            }
+          );
+        });
+
+        return app->exec();
+      }
+    '';
+
+  in runCommandCC "get-captcha" {
+    nativeBuildInputs = [ pkgconfig ];
+    buildInputs = [ qt5.qtbase qt5.qtwebengine ];
+  } ''
+    g++ $(pkg-config --libs --cflags Qt5WebEngineWidgets) \
+      -Wall -std=c++11 -o "$out" ${application}
+  '';
+
   humbleAPI = pythonPackages.buildPythonPackage rec {
     name = "humblebundle-${version}";
     version = "0.1.1";
@@ -24,7 +95,7 @@
   pyStr = str: "'${stdenv.lib.escape ["'" "\\"] str}'";
 
   getDownloadURL = writeText "gethburl.py" ''
-    import sys, humblebundle
+    import socket, sys, time, humblebundle
 
     def get_products(client):
       gamekeys = client.get_gamekeys()
@@ -51,8 +122,31 @@
             print >>sys.stderr, "  " + ds.name
           raise SystemExit(1)
 
+    def login_with_captcha(hb):
+      print >>sys.stderr, "Solving a captcha is required to log in."
+      print >>sys.stderr, "Please run " ${pyStr (toString getCaptcha)} " now."
+      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+      print >>sys.stderr, "Waiting for connection",
+      i = 0
+      while sock.connect_ex(("127.0.0.1", 18123)) != 0:
+        time.sleep(0.1)
+        if i % 10 == 0:
+          sys.stderr.write('.')
+          sys.stderr.flush()
+        i += 1
+      print >>sys.stderr, " connected."
+      print >>sys.stderr, "Waiting for captcha to be solved..."
+      response = sock.recv(4096)
+      sock.close()
+      print >>sys.stderr, "Captcha solved correctly, logging in."
+      hb.login(${pyStr email}, ${pyStr password}, recaptcha_response=response)
+
     hb = humblebundle.HumbleApi()
-    hb.login(${pyStr email}, ${pyStr password})
+    try:
+      hb.login(${pyStr email}, ${pyStr password})
+    except humblebundle.exceptions.HumbleCaptchaException:
+      login_with_captcha(hb)
+
     products = dict(get_products(hb))
     dstruct = find_download(products)