UNPKG

gplayapi-ts

Version:
146 lines 4.65 kB
import { promises as fs } from "fs"; import { Pixel3a } from "../devices/factory"; import { GPTokenExpiredError, GPNetworkError } from "../errors"; import { doRequest, createDefaultHeaders } from "../utils/network"; import { unmarshalResponseWrapper } from "../utils/parser"; import { AuthEndpoint } from "./endpoints/auth"; import { AppsEndpoint } from "./endpoints/apps"; import { LibraryEndpoint } from "./endpoints/library"; import { HttpStatusCode } from "../models/common"; class GooglePlayClient { authData; deviceInfo; sessionFile; auth; apps; library; constructor(authData, deviceInfo = Pixel3a) { this.authData = authData; this.deviceInfo = deviceInfo; this.auth = new AuthEndpoint( this.authData, this.deviceInfo, () => this.getAuthHeaders(), (url, options) => this.doAuthedReq(url, options) ); this.apps = new AppsEndpoint( (url, options) => this.doAuthedReq(url, options) ); this.library = new LibraryEndpoint( (url, options) => this.doAuthedReq(url, options), (packageName) => this.getAppDetails(packageName) ); } static async newClient(email, aasToken) { return GooglePlayClient.newClientWithDeviceInfo(email, aasToken, Pixel3a); } static async newClientWithDeviceInfo(email, aasToken, deviceInfo) { const authData = { email, aasToken, locale: "en_GB" }; const client = new GooglePlayClient(authData, deviceInfo); await client.auth.generateGsfId(); const deviceConfigRes = await client.auth.uploadDeviceConfig(); authData.deviceConfigToken = deviceConfigRes.uploadDeviceConfigToken; const token = await client.auth.generateGPToken(); authData.authToken = token; await client.auth.toc(); return client; } async saveSession(file) { await fs.writeFile(file, JSON.stringify(this.authData, null, 2)); } static async loadSession(file) { return GooglePlayClient.loadSessionWithDeviceInfo(file, Pixel3a); } static async loadSessionWithDeviceInfo(file, deviceInfo) { const data = await fs.readFile(file, "utf-8"); const authData = JSON.parse(data); const client = new GooglePlayClient(authData, deviceInfo); return client; } async _doAuthedReq(url, options = {}) { const { data, status } = await doRequest(url, { ...options, headers: { ...this.getDefaultHeaders(), ...options.headers || {} } }); if (status === HttpStatusCode.UNAUTHORIZED) { throw new GPTokenExpiredError(); } if (status >= 400) { throw new GPNetworkError(`Request failed with status ${status}`, status); } const resp = await unmarshalResponseWrapper(data); return resp.payload || null; } async doAuthedReq(url, options = {}) { try { return await this._doAuthedReq(url, options); } catch (error) { if (error instanceof GPTokenExpiredError) { await this.auth.regenerateGPToken(); if (this.sessionFile) { await this.saveSession(this.sessionFile); } return await this._doAuthedReq(url, options); } throw error; } } getAuthHeaders() { return { App: "com.google.android.gms", "User-Agent": this.deviceInfo.authUserAgent, ...this.authData.gsfId && { Device: this.authData.gsfId } }; } getDefaultHeaders() { const data = this.authData; const headers = createDefaultHeaders( this.deviceInfo.userAgent, data.gsfId, data.authToken ); if (data.deviceCheckInConsistencyToken) { headers["X-Dfe-Device-Checkin-Consistency-Token"] = data.deviceCheckInConsistencyToken; } if (data.deviceConfigToken) { headers["X-Dfe-Device-Config-Token"] = data.deviceConfigToken; } if (data.dfeCookie) { headers["X-Dfe-Cookie"] = data.dfeCookie; } if (this.deviceInfo.simOperator) { headers["X-Dfe-Mccmnc"] = this.deviceInfo.simOperator; } return headers; } // Convenience methods async getAppDetails(packageName) { return this.apps.getAppDetails(packageName); } async getBuyResponse(packageName, version) { return this.library.getBuyResponse(packageName, version); } async getDeliveryResponse(packageName, version) { return this.library.getDeliveryResponse(packageName, version); } async purchase(packageName, version) { return this.library.purchase(packageName, version); } async generateGsfId() { return this.auth.generateGsfId(); } async regenerateGPToken() { return this.auth.regenerateGPToken(); } } export { GooglePlayClient }; //# sourceMappingURL=client.mjs.map