Browse Source

- Revert login using the token method
- Use the cloudscraper layer on top of request to pass through the cloudfare browser check
- switch from tsd to typings

Godzil 11 months ago
parent
commit
b96efacbd2
4 changed files with 77 additions and 64 deletions
  1. 4 3
      package.json
  2. 60 28
      src/request.ts
  3. 0 33
      tsd.json
  4. 13 0
      typings.json

+ 4 - 3
package.json

@@ -19,19 +19,20 @@
   "dependencies": {
     "big-integer": "1.4.4",
     "cheerio": "0.22.0",
+    "cloudscraper": "1.4.1",
     "commander": "2.6.0",
     "mkdirp": "0.5.0",
     "request": "2.74.0",
     "xml2js": "0.4.5"
   },
   "devDependencies": {
-    "tsd": "0.5.7",
+    "typing": "2.1.0",
     "tslint": "2.3.0-beta",
     "typescript": "1.5.0-beta"
   },
   "scripts": {
-    "prepublish": "npm run tsd && tsc",
+    "prepublish": "npm run types && tsc",
     "test": "node ts --only-test",
-    "tsd": "tsd reinstall -o -s"
+    "types": "typings install"
   }
 }

+ 60 - 28
src/request.ts

@@ -1,8 +1,8 @@
 'use strict';
 import request = require('request');
 import cheerio = require('cheerio');
-import log  = require('./log');
-
+import log = require('./log');
+var cloudscraper = require('cloudscraper');
 var isAuthenticated = false;
 var isPremium = false;
 
@@ -17,7 +17,7 @@ var defaultHeaders: request.Headers = {
 export function get(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
   authenticate(config, err => {
     if (err) return done(err);
-    request.get(modify(options), (err: Error, response: any, body: any) => {
+    cloudscraper.request(modify(options, 'GET'), (err: Error, response: any, body: any) => {
       if (err) return done(err);
       done(null, typeof body === 'string' ? body : String(body));
     });
@@ -30,7 +30,7 @@ export function get(config: IConfig, options: request.Options, done: (err: Error
 export function post(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
   authenticate(config, err => {
     if (err) return done(err);
-    request.post(modify(options), (err: Error, response: any, body: any) => {
+    cloudscraper.request(modify(options, 'POST'), (err: Error, response: any, body: any) => {
       if (err) return done(err);
       done(null, typeof body === 'string' ? body : String(body));
     });
@@ -49,41 +49,72 @@ function authenticate(config: IConfig, done: (err: Error) => void) {
     headers: defaultHeaders,
     jar: true,
     gzip: false,
-    url: 'https://www.crunchyroll.com/?a=formhandler&formname=RpcApiUser_Login&name=' + config.user + '&password=' + config.pass
+    method: 'GET',
+    url: 'https://www.crunchyroll.com/login'
   };
 
-  request(options, (err: Error, rep: string, body: string) =>
+  // request(options, (err: Error, rep: string, body: string) =>
+  cloudscraper.request(options, (err: Error, rep: string, body: string) =>
   {
     if (err) return done(err);
-    /* The page return with a meta based redirection, as we wan't to check that everything is fine, reload
-     * the main page. A bit convoluted, but more sure.
-     */
+
+    var $ = cheerio.load(body);
+
+    /* Get the token from the login page */
+    var token = $('input[name="login_form[_token]"]').attr('value');
+    if (token === '') return done(new Error('Can`t find token!'));
+
     var options =
     {
       headers: defaultHeaders,
+      form:
+      {
+        'login_form[redirect_url]': '/',
+        'login_form[name]': config.user,
+        'login_form[password]': config.pass,
+        'login_form[_token]': token
+      },
       jar: true,
-      url: 'http://www.crunchyroll.com/'
+      gzip: false,
+      method: 'POST',
+      url: 'https://www.crunchyroll.com/login'
     };
-    request(options, (err: Error, rep: string, body: string) =>
+    // request.post(options, (err: Error, rep: string, body: string) =>
+    cloudscraper.request(options, (err: Error, rep: string, body: string) =>
     {
       if (err) return done(err);
-      var $ = cheerio.load(body);
-      /* Check if auth worked */
-      var regexps = /ga\(\'set\', \'dimension[5-8]\', \'([^']*)\'\);/g;
-      var dims = regexps.exec($('script').text());
-      for (var i = 1; i < 5; i++)
+      /* The page return with a meta based redirection, as we wan't to check that everything is fine, reload
+       * the main page. A bit convoluted, but more sure.
+       */
+      var options =
       {
-        if ((dims[i] !== undefined) && (dims[i] !== '') && (dims[i] !== 'not-registered')) { isAuthenticated = true; }
-        if ((dims[i] === 'premium') || (dims[i] === 'premiumplus')) { isPremium = true; }
-      }
-      if (isAuthenticated === false)
+        headers: defaultHeaders,
+        jar: true,
+        url: 'http://www.crunchyroll.com/',
+        method: 'GET'
+      };
+
+      cloudscraper.request(options, (err: Error, rep: string, body: string) =>
       {
-        var error = $('ul.message, li.error').text();
-        return done(new Error('Authentication failed: ' + error));
-      }
-      if (isPremium === false) { log.warn('Do not use this app without a premium account.'); }
-      else { log.info('You have a premium account! Good!'); }
-      done(null);
+        if (err) return done(err);
+        var $ = cheerio.load(body);
+        /* Check if auth worked */
+        var regexps = /ga\(\'set\', \'dimension[5-8]\', \'([^']*)\'\);/g;
+        var dims = regexps.exec($('script').text());
+        for (var i = 1; i < 5; i++)
+        {
+          if ((dims[i] !== undefined) && (dims[i] !== '') && (dims[i] !== 'not-registered')) { isAuthenticated = true; }
+          if ((dims[i] === 'premium') || (dims[i] === 'premiumplus')) { isPremium = true; }
+        }
+        if (isAuthenticated === false)
+        {
+          var error = $('ul.message, li.error').text();
+          return done(new Error('Authentication failed: ' + error));
+        }
+        if (isPremium === false) { log.warn('Do not use this app without a premium account.'); }
+        else { log.info('You have a premium account! Good!'); }
+        done(null);
+      });
     });
   });
 }
@@ -91,11 +122,12 @@ function authenticate(config: IConfig, done: (err: Error) => void) {
 /**
  * Modifies the options to use the authenticated cookie jar.
  */
-function modify(options: string|request.Options): request.Options {
+function modify(options: string|request.Options, reqMethod: string): request.Options {
   if (typeof options !== 'string') {
     options.jar = true;
     options.headers = defaultHeaders;
+    options.method = reqMethod;
     return options;
   }
-  return {jar: true, headers: defaultHeaders, url: options.toString()};
+  return { jar: true, headers: defaultHeaders, url: options.toString(), method: reqMethod};
 }

+ 0 - 33
tsd.json

@@ -1,33 +0,0 @@
-{
-  "version": "v4",
-  "repo": "borisyankov/DefinitelyTyped",
-  "ref": "master",
-  "path": "typings",
-  "bundle": "typings/tsd.d.ts",
-  "installed": {
-    "node/node.d.ts": {
-      "commit": "3882d337bb0808cde9fe4c08012508a48c135482"
-    },
-    "commander/commander.d.ts": {
-      "commit": "3882d337bb0808cde9fe4c08012508a48c135482"
-    },
-    "xml2js/xml2js.d.ts": {
-      "commit": "3882d337bb0808cde9fe4c08012508a48c135482"
-    },
-    "cheerio/cheerio.d.ts": {
-      "commit": "3882d337bb0808cde9fe4c08012508a48c135482"
-    },
-    "mkdirp/mkdirp.d.ts": {
-      "commit": "3882d337bb0808cde9fe4c08012508a48c135482"
-    },
-    "request/request.d.ts": {
-      "commit": "3882d337bb0808cde9fe4c08012508a48c135482"
-    },
-    "big-integer/big-integer.d.ts": {
-      "commit": "3882d337bb0808cde9fe4c08012508a48c135482"
-    },
-    "form-data/form-data.d.ts": {
-      "commit": "3882d337bb0808cde9fe4c08012508a48c135482"
-    }
-  }
-}

+ 13 - 0
typings.json

@@ -0,0 +1,13 @@
+{
+  "name": "crunchy",
+  "globalDependencies": {
+    "node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
+    "commander": "github:DefinitelyTyped/DefinitelyTyped/commander/commander.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
+    "xml2js": "github:DefinitelyTyped/DefinitelyTyped/xml2js/xml2js.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
+    "cheerio": "github:DefinitelyTyped/DefinitelyTyped/cheerio/cheerio.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
+    "mkdirp": "github:DefinitelyTyped/DefinitelyTyped/mkdirp/mkdirp.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
+    "request": "github:DefinitelyTyped/DefinitelyTyped/request/request.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
+    "big-integer": "github:DefinitelyTyped/DefinitelyTyped/big-integer/big-integer.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
+    "form-data": "github:DefinitelyTyped/DefinitelyTyped/form-data/form-data.d.ts#3882d337bb0808cde9fe4c08012508a48c135482"
+  }
+}