Skip to content

Commit

Permalink
Add !gota command
Browse files Browse the repository at this point in the history
  • Loading branch information
luk1337 committed Nov 13, 2024
1 parent 29b61ed commit 04cbbb0
Show file tree
Hide file tree
Showing 8 changed files with 523 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
__pycache__/
.envrc
praw.ini
proto/*_pb2.py
.direnv/
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ RUN GO111MODULE=on go install github.com/DarthSim/overmind/v2@latest
FROM python:3.11-alpine
COPY --from=overmind /go/bin/overmind /usr/local/bin/overmind

RUN apk add --no-cache curl build-base tmux redis git
RUN apk add --no-cache curl build-base tmux redis git protoc
RUN curl -L https://github.com/oliver006/redis_exporter/releases/download/v1.31.4/redis_exporter-v1.31.4.linux-amd64.tar.gz -o exporter.tgz \
&& tar xvzf exporter.tgz \
&& cp redis_exporter-*/redis_exporter /usr/local/bin/redis_exporter \
Expand Down
108 changes: 108 additions & 0 deletions cogs/gota.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import asyncio
import binascii
import gzip
import io
import os
import random

import discord
import requests
from discord.ext import commands

from proto import checkin_generator_pb2


class GoogleOTA(commands.Cog):
HEADERS = {
'accept-encoding': 'gzip, deflate',
'content-encoding': 'gzip',
'content-type': 'application/x-protobuffer',
}

@commands.Cog.listener()
async def on_ready(self):
print(f"Loaded {__name__}")

@commands.command(hidden=True)
async def gota(self, ctx, fingerprint):
checkin_request = checkin_generator_pb2.AndroidCheckinRequest()
checkin_request.imei = self.generate_imei()
checkin_request.id = 0
checkin_request.digest = self.generate_digest()
checkin_request.checkin.build.id = fingerprint
checkin_request.checkin.build.timestamp = 0
checkin_request.checkin.build.device = fingerprint.split('/')[2].split(':')[0]
checkin_request.checkin.lastCheckinMsec = 0
checkin_request.checkin.roaming = "WIFI::"
checkin_request.checkin.userNumber = 0
checkin_request.checkin.deviceType = 2
checkin_request.checkin.voiceCapable = False
checkin_request.checkin.unknown19 = "WIFI"
checkin_request.locale = 'en-US'
checkin_request.macAddr.append(self.generate_mac())
checkin_request.timeZone = 'America/New_York'
checkin_request.version = 3
checkin_request.serialNumber = self.generate_serial()
checkin_request.macAddrType.append('wifi')
checkin_request.fragment = 0
checkin_request.userSerialNumber = 0
checkin_request.fetchSystemUpdates = 1
checkin_request.unknown30 = 0

data = io.BytesIO()

with gzip.GzipFile(fileobj=data, mode='wb') as f:
f.write(checkin_request.SerializeToString())

resp = requests.post('https://android.googleapis.com/checkin',
data=data.getvalue(),
headers=self.HEADERS)

checkin_response = checkin_generator_pb2.AndroidCheckinResponse()
checkin_response.ParseFromString(resp.content)

update_title = None
update_url = None

for entry in checkin_response.setting:
if entry.name == b'update_title':
update_title = entry.value.decode()
elif entry.name == b'update_url':
update_url = entry.value.decode()

if update_title and update_url:
embed = discord.Embed(title=update_title)
embed.add_field(name="URL", value=update_url, inline=False)
await self.reply_and_delete(ctx, content=None, embed=embed)
else:
await self.reply_and_delete(ctx, content='Not found :(')

@staticmethod
def generate_imei():
imei = [random.randint(0, 9) for _ in range(15)]
return ''.join(map(str, imei))

@staticmethod
def generate_mac():
return binascii.b2a_hex(os.urandom(6))

@staticmethod
def generate_serial():
serial = [random.choice('0123456789abcdef') for _ in range(8)]
return ''.join(serial)

@staticmethod
def generate_digest():
digest = [random.choice('0123456789abcdef') for _ in range(40)]
return '1-' + ''.join(digest)

@staticmethod
async def reply_and_delete(ctx, *args, **kwargs):
message = await ctx.reply(*args, **kwargs)
await asyncio.sleep(60)
await message.delete()
await ctx.message.delete()


async def setup(bot):
await bot.add_cog(GoogleOTA(bot))
10 changes: 9 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import asyncio
import os
import subprocess
from glob import glob

import discord
from discord.ext import commands

dir_path = os.path.dirname(os.path.realpath(__file__))

for name in glob(f"{dir_path}/proto/*.proto"):
subprocess.run(
["protoc", "--proto_path=./proto", "--python_out=./proto", os.path.basename(name)],
cwd=dir_path)

class Bot(commands.Bot):
def __init__(self, command_prefix, *, intents, **options):
super().__init__(command_prefix, intents=intents, **options)
Expand Down
96 changes: 96 additions & 0 deletions proto/android_checkin.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Logging information for Android "checkin" events (automatic, periodic
// requests made by Android devices to the server).

syntax = "proto2";

option optimize_for = LITE_RUNTIME;
package checkin_proto;

// Build characteristics unique to the Chrome browser, and Chrome OS
message ChromeBuildProto {
enum Platform {
PLATFORM_WIN = 1;
PLATFORM_MAC = 2;
PLATFORM_LINUX = 3;
PLATFORM_CROS = 4;
PLATFORM_IOS = 5;
// Just a placeholder. Likely don't need it due to the presence of the
// Android GCM on phone/tablet devices.
PLATFORM_ANDROID = 6;
}

enum Channel {
CHANNEL_STABLE = 1;
CHANNEL_BETA = 2;
CHANNEL_DEV = 3;
CHANNEL_CANARY = 4;
CHANNEL_UNKNOWN = 5; // for tip of tree or custom builds
}

// The platform of the device.
optional Platform platform = 1;

// The Chrome instance's version.
optional string chrome_version = 2;

// The Channel (build type) of Chrome.
optional Channel channel = 3;
}

// Information sent by the device in a "checkin" request.
message AndroidCheckinProto {
// Miliseconds since the Unix epoch of the device's last successful checkin.
optional int64 last_checkin_msec = 2;

// The current MCC+MNC of the mobile device's current cell.
optional string cell_operator = 6;

// The MCC+MNC of the SIM card (different from operator if the
// device is roaming, for instance).
optional string sim_operator = 7;

// The device's current roaming state (reported starting in eclair builds).
// Currently one of "{,not}mobile-{,not}roaming", if it is present at all.
optional string roaming = 8;

// For devices supporting multiple user profiles (which may be
// supported starting in jellybean), the ordinal number of the
// profile that is checking in. This is 0 for the primary profile
// (which can't be changed without wiping the device), and 1,2,3,...
// for additional profiles (which can be added and deleted freely).
optional int32 user_number = 9;

// Class of device. Indicates the type of build proto
// (IosBuildProto/ChromeBuildProto/AndroidBuildProto)
// That is included in this proto
optional DeviceType type = 12 [default = DEVICE_ANDROID_OS];

// For devices running MCS on Chrome, build-specific characteristics
// of the browser. There are no hardware aspects (except for ChromeOS).
// This will only be populated for Chrome builds/ChromeOS devices
optional checkin_proto.ChromeBuildProto chrome_build = 13;

// Note: Some of the Android specific optional fields were skipped to limit
// the protobuf definition.
// Next 14
}

// enum values correspond to the type of device.
// Used in the AndroidCheckinProto and Device proto.
enum DeviceType {
// Android Device
DEVICE_ANDROID_OS = 1;

// Apple IOS device
DEVICE_IOS_OS = 2;

// Chrome browser - Not Chrome OS. No hardware records.
DEVICE_CHROME_BROWSER = 3;

// Chrome OS
DEVICE_CHROME_OS = 4;
}
152 changes: 152 additions & 0 deletions proto/checkin-generator.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
syntax = "proto2";

package tutorial;

message AndroidBuildProto {
message ClientGroups {
optional int32 version = 1;
optional string name = 2;
}
optional string id = 1;
optional string hardware = 2;
optional string brand = 3;
optional string radio = 4;
optional string bootloader = 5;
optional string clientId = 6;
optional int64 timestamp = 7;
optional int32 googleServices = 8;
optional string device = 9;
optional int32 sdkVersion = 10;
optional string model = 11;
optional string manufacturer = 12;
optional string product = 13;
optional bool otaInstalled = 14;
repeated ClientGroups groups = 15;
optional string securityPatch = 19;
}

message AndroidCheckinReasonProto {
optional int32 reasonType = 1;
optional int32 attemptCount = 2;
optional string sourcePackage = 3;
optional string sourceClass = 4;
optional bool sourceForce = 5;
}

message AndroidCheckinProto {
optional AndroidBuildProto build = 1;
optional int64 lastCheckinMsec = 2;
repeated AndroidEventProto event = 3;
repeated AndroidStatisticProto stat = 4;
repeated string requestedGroup = 5; // unused
optional string cellOperator = 6;
optional string simOperator = 7;
optional string roaming = 8;
optional int32 userNumber = 9;
optional int32 deviceType = 14 [default = 1];
optional AndroidCheckinReasonProto reason = 15;
optional bool voiceCapable = 18;
optional string unknown19 = 19; // unclear what this is for, but exists
}

message AndroidEventProto {
optional string tag = 1;
optional string value = 2;
optional int64 timeMsec = 3;
}

message AndroidStatisticProto {
optional string tag = 1;
optional int32 count = 2;
optional float sum = 3;
}

message DeviceConfigurationProto {
optional int32 touchScreen = 1;
optional int32 keyboard = 2;
optional int32 navigation = 3;
optional int32 screenLayout = 4;
optional bool hasHardKeyboard = 5;
optional bool hasFiveWayNavigation = 6;
optional int32 screenDensity = 7;
optional int32 glEsVersion = 8;
repeated string systemSharedLibrary = 9;
repeated string systemAvailableFeature = 10;
repeated string nativePlatform = 11;
optional int32 screenWidth = 12;
optional int32 screenHeight = 13;
repeated string systemSupportedLocale = 14;
repeated string glExtension = 15;
optional int32 deviceClass = 16;
optional int32 maxApkDownloadSizeMb = 17[default = 50];
optional int32 smallestScreenWidthDP = 18;
optional int32 lowRamDevice = 19[default=0];
optional int64 totalMemoryBytes = 20[default=8354971648];
optional int32 maxNumOf_CPUCores = 21[default=8];
repeated DeviceFeature deviceFeature = 26;
optional bool keyGuardDeviceSecure = 28[default=true];
optional int32 unknown30 = 30[default=4];
}

message DeviceFeature {
optional string name = 1;
optional int32 value = 2;
}

message AndroidCheckinRequest {
optional string imei = 1; // used by GSM phones
optional int64 id = 2[default=0];
optional string digest = 3;
optional AndroidCheckinProto checkin = 4;
optional string desiredBuild = 5; // DEPRECATED: Use AndroidCheckinProto.requestedGroup
optional string locale = 6;
optional int64 loggingId = 7;
optional string marketCheckin = 8; // unused
repeated string macAddr = 9;
optional string meid = 10; // used by CDMA phones
repeated string accountCookie = 11;
optional string timeZone = 12;
optional fixed64 securityToken = 13;
optional int32 version = 14;
repeated string otaCert = 15;
optional string serialNumber = 16;
optional string esn = 17; // used in CDMA networks
optional DeviceConfigurationProto deviceConfiguration = 18;
repeated string macAddrType = 19;
optional int32 fragment = 20;
optional string userName = 21;
optional int32 userSerialNumber = 22;
optional string droidguardResult = 24;
optional int32 fetchSystemUpdates = 29;
optional int32 unknown30 = 30;
}

message AndroidCheckinResponse {
optional bool statsOk = 1;
repeated AndroidIntentProto intent = 2;
optional int64 timeMsec = 3;
optional string digest = 4;
repeated GservicesSetting setting = 5;
optional bool marketOk = 6;
optional fixed64 androidId = 7;
optional fixed64 securityToken = 8;
optional bool settingsDiff = 9;
repeated string deleteSetting = 10;
optional string deviceDataVersionInfo = 12;
}

message AndroidIntentProto {
optional string action = 1;
optional string dataUri = 2;
optional string mimeType = 3;
optional string javaClass = 4;
repeated group Extra = 5 {
optional string name = 6;
optional string value = 7;
}
}

message GservicesSetting {
optional bytes name = 1;
optional bytes value = 2;
}
Loading

0 comments on commit 04cbbb0

Please sign in to comment.