"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.State = void 0;
const lodash_1 = __importDefault(require("lodash"));
const bluebird_1 = __importDefault(require("bluebird"));
const chance_1 = __importDefault(require("chance"));
const request_1 = require("request");
const tough_cookie_1 = require("tough-cookie");
const Constants = __importStar(require("./constants"));
const errors_1 = require("../errors");
const decorators_1 = require("../decorators");
const debug_1 = __importDefault(require("debug"));
const supportedCapabilities = [
    {
        name: "SUPPORTED_SDK_VERSIONS",
        value: "13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0,32.0,33.0,34.0,35.0,36.0,37.0,38.0,39.0,40.0,41.0,42.0,43.0,44.0,45.0,46.0,47.0,48.0,49.0,50.0,51.0,52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,60.0,61.0,62.0,63.0,64.0,65.0,66.0",
    },
    {
        name: "FACE_TRACKER_VERSION",
        value: 12,
    },
    {
        name: "segmentation",
        value: "segmentation_enabled",
    },
    {
        name: "COMPRESSION",
        value: "ETC2_COMPRESSION",
    },
    {
        name: "world_tracker",
        value: "world_tracker_enabled",
    },
    {
        name: "gyroscope",
        value: "gyroscope_enabled",
    },
];
const builds = [
    "NMF26X",
    "MMB29M",
    "MRA58K",
    "NRD90M",
    "MRA58K",
    "OPM1.171019.011",
    "IMM76L",
    "JZO54K",
    "JDQ39",
    "JLS36I",
    "KTU84P",
    "LRX22C",
    "LMY48M",
    "MMB29V",
    "NRD91N",
    "N2G48C",
];
const devices = [
    "25/7.1.1; 440dpi; 1080x1920; Xiaomi; Mi Note 3; jason; qcom",
    "23/6.0.1; 480dpi; 1080x1920; Xiaomi; Redmi Note 3; kenzo; qcom",
    "23/6.0; 480dpi; 1080x1920; Xiaomi; Redmi Note 4; nikel; mt6797",
    "24/7.0; 480dpi; 1080x1920; Xiaomi/xiaomi; Redmi Note 4; mido; qcom",
    "23/6.0; 480dpi; 1080x1920; Xiaomi; Redmi Note 4X; nikel; mt6797",
    "27/8.1.0; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi Note 5; whyred; qcom",
    "23/6.0.1; 480dpi; 1080x1920; Xiaomi; Redmi 4; markw; qcom",
    "27/8.1.0; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom",
    "25/7.1.2; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom",
    "26/8.0.0; 480dpi; 1080x1920; Xiaomi; MI 5; gemini; qcom",
    "27/8.1.0; 480dpi; 1080x1920; Xiaomi/xiaomi; Mi A1; tissot_sprout; qcom",
    "26/8.0.0; 480dpi; 1080x1920; Xiaomi; MI 6; sagit; qcom",
    "25/7.1.1; 440dpi; 1080x1920; Xiaomi; MI MAX 2; oxygen; qcom",
    "24/7.0; 480dpi; 1080x1920; Xiaomi; MI 5s; capricorn; qcom",
    "26/8.0.0; 480dpi; 1080x1920; samsung; SM-A520F; a5y17lte; samsungexynos7880",
    "26/8.0.0; 480dpi; 1080x2076; samsung; SM-G950F; dreamlte; samsungexynos8895",
    "26/8.0.0; 640dpi; 1440x2768; samsung; SM-G950F; dreamlte; samsungexynos8895",
    "26/8.0.0; 420dpi; 1080x2094; samsung; SM-G955F; dream2lte; samsungexynos8895",
    "26/8.0.0; 560dpi; 1440x2792; samsung; SM-G955F; dream2lte; samsungexynos8895",
    "24/7.0; 480dpi; 1080x1920; samsung; SM-A510F; a5xelte; samsungexynos7580",
    "26/8.0.0; 480dpi; 1080x1920; samsung; SM-G930F; herolte; samsungexynos8890",
    "26/8.0.0; 480dpi; 1080x1920; samsung; SM-G935F; hero2lte; samsungexynos8890",
    "26/8.0.0; 420dpi; 1080x2094; samsung; SM-G965F; star2lte; samsungexynos9810",
    "26/8.0.0; 480dpi; 1080x2076; samsung; SM-A530F; jackpotlte; samsungexynos7885",
    "24/7.0; 640dpi; 1440x2560; samsung; SM-G925F; zerolte; samsungexynos7420",
    "26/8.0.0; 420dpi; 1080x1920; samsung; SM-A720F; a7y17lte; samsungexynos7880",
    "24/7.0; 640dpi; 1440x2560; samsung; SM-G920F; zeroflte; samsungexynos7420",
    "24/7.0; 420dpi; 1080x1920; samsung; SM-J730FM; j7y17lte; samsungexynos7870",
    "26/8.0.0; 480dpi; 1080x2076; samsung; SM-G960F; starlte; samsungexynos9810",
    "26/8.0.0; 420dpi; 1080x2094; samsung; SM-N950F; greatlte; samsungexynos8895",
    "26/8.0.0; 420dpi; 1080x2094; samsung; SM-A730F; jackpot2lte; samsungexynos7885",
    "26/8.0.0; 420dpi; 1080x2094; samsung; SM-A605FN; a6plte; qcom",
    "26/8.0.0; 480dpi; 1080x1920; HUAWEI/HONOR; STF-L09; HWSTF; hi3660",
    "27/8.1.0; 480dpi; 1080x2280; HUAWEI/HONOR; COL-L29; HWCOL; kirin970",
    "26/8.0.0; 480dpi; 1080x2032; HUAWEI/HONOR; LLD-L31; HWLLD-H; hi6250",
    "26/8.0.0; 480dpi; 1080x2150; HUAWEI; ANE-LX1; HWANE; hi6250",
    "26/8.0.0; 480dpi; 1080x2032; HUAWEI; FIG-LX1; HWFIG-H; hi6250",
    "27/8.1.0; 480dpi; 1080x2150; HUAWEI/HONOR; COL-L29; HWCOL; kirin970",
    "26/8.0.0; 480dpi; 1080x2038; HUAWEI/HONOR; BND-L21; HWBND-H; hi6250",
    "23/6.0.1; 420dpi; 1080x1920; LeMobile/LeEco; Le X527; le_s2_ww; qcom",
];
class State {
    constructor() {
        this.constants = Constants;
        this.supportedCapabilities = supportedCapabilities;
        this.language = "en_US";
        this.timezoneOffset = String(new Date().getTimezoneOffset() * -60);
        this.radioType = "wifi-none";
        this.capabilitiesHeader = "3brTvwE=";
        this.connectionTypeHeader = "WIFI";
        this.isLayoutRTL = false;
        this.euDCEnabled = undefined;
        this.adsOptOut = false;
        this.thumbnailCacheBustingValue = 1000;
        this.cookieStore = new tough_cookie_1.MemoryCookieStore();
        this.cookieJar = (0, request_1.jar)(this.cookieStore);
        this.checkpoint = null;
        this.challenge = null;
        this.clientSessionIdLifetime = 1200000;
        this.pigeonSessionIdLifetime = 1200000;
    }
    get signatureKey() {
        return this.constants.SIGNATURE_KEY;
    }
    get signatureVersion() {
        return this.constants.SIGNATURE_VERSION;
    }
    get userBreadcrumbKey() {
        return this.constants.BREADCRUMB_KEY;
    }
    get appVersion() {
        return this.constants.APP_VERSION;
    }
    get appVersionCode() {
        return this.constants.APP_VERSION_CODE;
    }
    get fbAnalyticsApplicationId() {
        return this.constants.FACEBOOK_ANALYTICS_APPLICATION_ID;
    }
    get fbOtaFields() {
        return this.constants.FACEBOOK_OTA_FIELDS;
    }
    get fbOrcaApplicationId() {
        return this.constants.FACEBOOK_ORCA_APPLICATION_ID;
    }
    get loginExperiments() {
        return this.constants.LOGIN_EXPERIMENTS;
    }
    get experiments() {
        return this.constants.EXPERIMENTS;
    }
    get bloksVersionId() {
        return this.constants.BLOKS_VERSION_ID;
    }
    get clientSessionId() {
        return this.generateTemporaryGuid("clientSessionId", this.clientSessionIdLifetime);
    }
    get pigeonSessionId() {
        return this.generateTemporaryGuid("pigeonSessionId", this.pigeonSessionIdLifetime);
    }
    get appUserAgent() {
        return `Instagram ${this.appVersion} Android (${this.deviceString}; ${this.language}; ${this.appVersionCode})`;
    }
    get webUserAgent() {
        return `Mozilla/5.0 (Linux; Android ${this.devicePayload.android_release}; ${this.devicePayload.model} Build/${this.build}; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.110 Mobile Safari/537.36 ${this.appUserAgent}`;
    }
    get devicePayload() {
        const deviceParts = this.deviceString.split(";");
        const [android_version, android_release] = deviceParts[0].split("/");
        const [manufacturer] = deviceParts[3].split("/");
        const model = deviceParts[4];
        return {
            android_version,
            android_release,
            manufacturer,
            model,
        };
    }
    get batteryLevel() {
        const chance = new chance_1.default(this.deviceId);
        const percentTime = chance.integer({ min: 200, max: 600 });
        return 100 - (Math.round(Date.now() / 1000 / percentTime) % 100);
    }
    get isCharging() {
        const chance = new chance_1.default(`${this.deviceId}${Math.round(Date.now() / 10800000)}`);
        return chance.bool();
    }
    get challengeUrl() {
        if (!this.checkpoint) {
            throw new errors_1.IgNoCheckpointError();
        }
        return `/api/v1${this.checkpoint.challenge.api_path}`;
    }
    get cookieCsrfToken() {
        try {
            return this.extractCookieValue("csrftoken");
        }
        catch (_a) {
            State.stateDebug('csrftoken lookup failed, returning "missing".');
            return "missing";
        }
    }
    get cookieUserId() {
        return this.extractCookieValue("ds_user_id");
    }
    get cookieUsername() {
        return this.extractCookieValue("ds_user");
    }
    isExperimentEnabled(experiment) {
        return this.experiments.includes(experiment);
    }
    extractCookie(key) {
        const cookies = this.cookieJar.getCookies(this.constants.HOST);
        return lodash_1.default.find(cookies, { key }) || null;
    }
    extractCookieValue(key) {
        const cookie = this.extractCookie(key);
        if (cookie === null) {
            State.stateDebug(`Could not find ${key}`);
            throw new errors_1.IgCookieNotFoundError(key);
        }
        return cookie.value;
    }
    extractUserId() {
        try {
            return this.cookieUserId;
        }
        catch (e) {
            if (this.challenge === null || !this.challenge.user_id) {
                throw new errors_1.IgUserIdNotFoundError();
            }
            return String(this.challenge.user_id);
        }
    }
    async deserializeCookieJar(cookies) {
        this.cookieJar["_jar"] = await bluebird_1.default.fromCallback((cb) => tough_cookie_1.CookieJar.deserialize(cookies, this.cookieStore, cb));
    }
    async serializeCookieJar() {
        return bluebird_1.default.fromCallback((cb) => this.cookieJar["_jar"].serialize(cb));
    }
    async serialize() {
        const obj = {
            constants: this.constants,
            cookies: JSON.stringify(await this.serializeCookieJar()),
        };
        for (const [key, value] of Object.entries(this)) {
            obj[key] = value;
        }
        return obj;
    }
    async deserialize(state) {
        State.stateDebug(`Deserializing state of type ${typeof state}`);
        const obj = typeof state === "string" ? JSON.parse(state) : state;
        if (typeof obj !== "object") {
            State.stateDebug(`State deserialization failed, obj is of type ${typeof obj} (object expected)`);
            throw new TypeError("State isn't an object or serialized JSON");
        }
        State.stateDebug(`Deserializing ${Object.keys(obj).join(", ")}`);
        if (obj.constants) {
            this.constants = obj.constants;
            delete obj.constants;
        }
        if (obj.cookies) {
            await this.deserializeCookieJar(obj.cookies);
            delete obj.cookies;
        }
        for (const [key, value] of Object.entries(obj)) {
            this[key] = value;
        }
    }
    generateDevice(seed) {
        const chance = new chance_1.default(seed);
        this.deviceString = chance.pickone(devices);
        const id = chance.string({
            pool: "abcdef0123456789",
            length: 16,
        });
        this.deviceId = `android-${id}`;
        this.uuid = chance.guid();
        this.phoneId = chance.guid();
        this.adid = chance.guid();
        this.build = chance.pickone(builds);
    }
    generateTemporaryGuid(seed, lifetime) {
        return new chance_1.default(`${seed}${this.deviceId}${Math.round(Date.now() / lifetime)}`).guid();
    }
}
State.stateDebug = (0, debug_1.default)("ig:state");
__decorate([
    (0, decorators_1.Enumerable)(false)
], State.prototype, "constants", void 0);
__decorate([
    (0, decorators_1.Enumerable)(false)
], State.prototype, "proxyUrl", void 0);
__decorate([
    (0, decorators_1.Enumerable)(false)
], State.prototype, "cookieStore", void 0);
__decorate([
    (0, decorators_1.Enumerable)(false)
], State.prototype, "cookieJar", void 0);
__decorate([
    (0, decorators_1.Enumerable)(false)
], State.prototype, "checkpoint", void 0);
__decorate([
    (0, decorators_1.Enumerable)(false)
], State.prototype, "challenge", void 0);
exports.State = State;
