import { createOutputDirectory } from "./io.js";
import { createOutputObject, } from "./output.js";
import { testSSL, testHttps } from "./connection.js";
import { filterKeywords, filterSocialPlatforms, mapLinksToParties, collectLinks, collectCookies, unsafeWebforms, } from "./collector_inspector.js";
import { BrowserSession } from "./browser-session.js";
import { getLocalStorage } from "../lib/tools.js";
export class Collector {
    constructor(args, logger) {
        // create the root folder structure
        createOutputDirectory(args.output, args.overwrite);
        let createOutputArgs = {
            firstPartyUri: args.firstPartyUri,
            taskDescription: args.taskDescription,
            title: args.title,
            url: args.url,
            screenshots: args.screenshots,
        };
        // create the output hash...
        this.output = createOutputObject(createOutputArgs);
        this.browserSession = null;
        this.pageSession = null;
        this.logger = logger;
        this.args = args;
    }
    async run() {
        // create browser, session, har, pagesession etc to be able to collect
        await this.createSession();
        this.logger.info("Done: Creating puppeteer chrome session");
        //test the ssl and https connection
        await this.testConnection();
        this.logger.info("Done: Testing connection using testHttps and testSSL");
        // go to the target url specified in the args - also possible to overload with a custom url.
        await this.getPage();
        this.logger.info("Done: Loading page");
        // ########################################################
        // Collect Links, Forms and Cookies to populate the output
        // ########################################################
        await this.collectScreenshots();
        this.logger.info("Done: Collecting screenshots");
        await this.collectLinks();
        this.logger.info("Done: Collecting links");
        await this.collectForms();
        this.logger.info("Done: Collecting forms");
        await this.collectCookies();
        this.logger.info("Done: Collecting cookies");
        await this.collectLocalStorage();
        this.logger.info("Done: Collecting local storage");
        await this.collectWebsocketLog();
        this.logger.info("Done: Collecting websocket log");
        // browse sample history and log to localstorage
        let browse_user_set = this.args.browseLink || [];
        await this.browseSamples(this.output.localStorage, browse_user_set);
        this.logger.info("Done: Browsing samples");
        // END OF BROWSING - discard the browser and page
        await this.endSession();
        this.logger.info("Done: Ending session");
        return {
            output: this.output,
            pageSession: this.pageSession,
            source: this.source,
        };
    }
    async createSession() {
        let browserArgs = {
            "--": this.args["--"],
            browserOptions: this.args.browserOptions,
            browserProfile: this.args.browserProfile,
            doNotTrack: this.args.dnt,
            doNotTrackJs: this.args.dntJs,
            headless: this.args.headless,
            linkLimit: this.args.max,
            outputPath: this.args.output,
            pageLoadTimeout: this.args.pageTimeout,
            sleep: this.args.sleep,
            cookies: this.args.setCookie,
            seed: this.args.seed,
            skipHeadRequest: this.args.skipHeadRequest,
        };
        this.browserSession = new BrowserSession(browserArgs, this.logger);
        await this.browserSession.create();
        this.output.browser.version = await this.browserSession.browser.version();
        this.output.browser.user_agent =
            await this.browserSession.browser.userAgent();
        this.pageSession = await this.browserSession.start(this.output);
    }
    async testConnection() {
        await testHttps(this.output.uri_ins, this.output, this.logger);
        await testSSL(this.output.uri_ins, this.args, this.logger, this.output);
    }
    async getPage(url = null) {
        if (!url) {
            url = this.output.uri_ins;
        }
        const response = await this.pageSession.gotoPage(url);
        if (response == null) {
            throw new Error("The collector was not able to access the page.");
        }
        await new Promise((resolve) => setTimeout(resolve, this.args.sleep)); // in ms
        // log redirects
        this.output.uri_redirects = response
            .request()
            .redirectChain()
            .map((req) => req.url());
        // log the destination uri after redirections
        this.output.uri_dest = this.pageSession.page.url();
        this.source = await this.pageSession.page.content();
        return response;
    }
    async collectScreenshots() {
        // record screenshots
        if (this.args.screenshots) {
            this.output.screenshots = await this.pageSession.takeScreenshots();
        }
    }
    async collectLinks() {
        // get all links from page
        const links = await collectLinks(this.pageSession.page, this.logger);
        let mappedLinks = await mapLinksToParties(links, this.pageSession.hosts, this.pageSession.refs_regexp);
        this.output.links.firstParty = mappedLinks.firstParty;
        this.output.links.thirdParty = mappedLinks.thirdParty;
        this.output.links.social = await filterSocialPlatforms(links);
        // prepare regexp to match links by their href or their caption
        this.output.links.keywords = await filterKeywords(links);
    }
    async collectCookies() {
        this.output.cookies = await collectCookies(this.pageSession.page, this.output.start_time);
    }
    async collectForms() {
        // unsafe webforms
        this.output.unsafeForms = await unsafeWebforms(this.pageSession.page);
    }
    async collectLocalStorage() {
        this.output.localStorage = await getLocalStorage(this.pageSession.page, this.logger, {});
    }
    async collectWebsocketLog() {
        this.output.websocketLog = this.pageSession.webSocketLog;
    }
    async browseSamples(localStorage, user_set = []) {
        this.output.browsing_history = await this.pageSession.browseSamples(this.pageSession.page, localStorage, this.output.uri_dest, this.output.links.firstParty, user_set);
    }
    async endSession() {
        if (this.browserSession) {
            await this.browserSession.end();
            this.browserSession = null;
        }
        this.output.end_time = new Date();
    }
    endPageSession() {
        this.pageSession = null;
    }
}
