diff --git a/src/scripts/classes/session.ts b/src/scripts/classes/session.ts index fcc62ee..564f8ea 100644 --- a/src/scripts/classes/session.ts +++ b/src/scripts/classes/session.ts @@ -3,9 +3,11 @@ // Core modules import * as fs from "fs"; import { promisify } from "util"; +import path from "path"; // Public modules from npm import md5 from "md5"; +import tough, { CookieJar } from "tough-cookie"; // Promisifed functions const areadfile = promisify(fs.readFile); @@ -19,12 +21,15 @@ export default class Session { /** * Max number of days the session is valid. */ - private readonly SESSION_TIME: number = 1; + private readonly SESSION_TIME: number = 3; + private readonly COOKIEJAR_FILENAME: string = "f95cookiejar.json"; private _path: string; private _isMapped: boolean; private _created: Date; private _hash: string; private _token: string; + private _cookieJar: CookieJar; + private _cookieJarPath: string; //#endregion Fields @@ -50,18 +55,27 @@ export default class Session { * Token used to login to F95Zone. */ public get token() { return this._token; } + /** + * Cookie holder. + */ + public get cookieJar() { return this._cookieJar; } //#endregion Getters /** * Initializes the session by setting the path for saving information to disk. */ - constructor(path: string) { - this._path = path; + constructor(p: string) { + this._path = p; this._isMapped = fs.existsSync(this.path); this._created = new Date(Date.now()); this._hash = null; this._token = null; + this._cookieJar = new tough.CookieJar(); + + // Define the path for the cookiejar + const basedir = path.dirname(p); + this._cookieJarPath = path.join(basedir, this.COOKIEJAR_FILENAME); } //#region Private Methods @@ -122,6 +136,10 @@ export default class Session { // Write data await awritefile(this.path, data); + + // Write cookiejar + const serializedJar = await this._cookieJar.serialize(); + await awritefile(this._cookieJarPath, JSON.stringify(serializedJar)); } /** @@ -134,9 +152,13 @@ export default class Session { const json = JSON.parse(data); // Assign values - this._created = json._created; + this._created = new Date(json._created); this._hash = json._hash; this._token = json._token; + + // Load cookiejar + const serializedJar = await areadfile(this._cookieJarPath, { encoding: 'utf-8', flag: 'r' }); + this._cookieJar = await CookieJar.deserialize(JSON.parse(serializedJar)); } } @@ -145,7 +167,11 @@ export default class Session { */ async delete(): Promise { if (this.isMapped) { + // Delete the session data await aunlinkfile(this.path); + + // Delete the cookiejar + await aunlinkfile(this._cookieJarPath); } } @@ -154,18 +180,22 @@ export default class Session { */ isValid(username: string, password: string): boolean { // Get the number of days from the file creation - const diff = this.dateDiffInDays(new Date(Date.now()), this._created); + const diff = this.dateDiffInDays(new Date(Date.now()), this.created); // The session is valid if the number of days is minor than SESSION_TIME - let valid = diff < this.SESSION_TIME; + const dateValid = diff < this.SESSION_TIME; - if(valid) { - // Check the _hash - const value = `${username}%%%${password}`; - valid = md5(value) === this._hash; - } + // Check the hash + const value = `${username}%%%${password}`; + const hashValid = md5(value) === this._hash; - return valid; + // Search for expired cookies + const jarValid = this._cookieJar + .getCookiesSync("https://f95zone.to") + .filter(el => el.TTL() === 0) + .length === 0; + + return dateValid && hashValid && jarValid; } //#endregion Public Methods diff --git a/src/scripts/network-helper.ts b/src/scripts/network-helper.ts index 0d0e701..b35890d 100644 --- a/src/scripts/network-helper.ts +++ b/src/scripts/network-helper.ts @@ -4,7 +4,6 @@ import axios, { AxiosResponse } from "axios"; import cheerio from "cheerio"; import axiosCookieJarSupport from "axios-cookiejar-support"; -import tough from "tough-cookie"; // Modules from file import shared from "./shared.js"; @@ -21,13 +20,25 @@ const userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) " + // @ts-ignore axiosCookieJarSupport.default(axios); +/** + * Common configuration used to send request via Axios. + */ const commonConfig = { + /** + * Headers to add to the request. + */ headers: { "User-Agent": userAgent, "Connection": "keep-alive" }, + /** + * Specify if send credentials along the request. + */ withCredentials: true, - jar: new tough.CookieJar() // Used to store the token in the PC + /** + * Jar of cookies to send along the request. + */ + jar: shared.session.cookieJar, }; /** @@ -38,6 +49,7 @@ export async function fetchHTML(url: string): Promise