Skip to content

Instantly share code, notes, and snippets.

@keyboardcrunch
Created March 10, 2019 02:54
Show Gist options
  • Save keyboardcrunch/c80c87cf563b8f575ae9e7ecb1f0487c to your computer and use it in GitHub Desktop.
Save keyboardcrunch/c80c87cf563b8f575ae9e7ecb1f0487c to your computer and use it in GitHub Desktop.
repurposed chrome extension download and extraction script
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Python Script to download the Chrome Extensions (CRX) file directly from the google chrome web store.
Referred from http://chrome-extension-downloader.com/how-does-it-work.php
"""
import argparse
import requests
import urllib.parse
import sys
import os
import fnmatch
import zipfile
__author__ = 'arul'
class ChromeAppDownloader():
CRX_URL = "https://clients2.google.com/service/update2/crx?" \
"response=redirect&prodversion=38.0&x=id%3D~~~~%26installsource%3Dondemand%26uc"
USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36"
global headers
headers = {
"User-Agent": USER_AGENT,
"Referer": "https://chrome.google.com",
}
def __init__(self):
pass
def download(self, _download_url_, _file_name_):
"""
Download the given URL into given filename.
:param _download_url_:
:param _file_name_:
:return:
"""
try:
# Download as Stream
r = requests.get(url=_download_url_, headers=headers, stream=True)
redirects = r.history
if len(redirects) > 0:
redirect_header = redirects[-1].headers
if "location" in redirect_header:
loc = redirect_header["location"]
uparse = urllib.parse.urlparse(loc)
splits = uparse.path.split("/")
_fname_ = splits[-1]
if _fname_:
_file_name_ = _fname_.replace("extension", _file_name_)
else:
_file_name_ += ".crx"
chunk_size = 16 * 1024
dowloaded_bytes = 0
with open(_file_name_, 'wb') as fd:
for chunk in r.iter_content(chunk_size):
fd.write(chunk)
return _file_name_
except Exception as e:
raise ValueError("Error in downloading %s " % _download_url_, e)
def parse(self, chrome_store_url):
"""
Validate the given input is chrome store URL or not.
Returning app ID and app Name from the URL
:param chrome_store_url:
:return:
"""
try:
# Try to validate the URL
uparse = urllib.parse.urlparse(chrome_store_url)
if uparse.netloc != "chrome.google.com":
raise ValueError("Not a valid URL %s" % chrome_store_url)
splits = uparse.path.split("/")
if not (len(splits) == 4 and uparse.path.startswith("/webstore/detail/")):
raise ValueError("Not a valid URL %s" % chrome_store_url)
except Exception as e:
pass
return splits[-1], splits[-2]
if __name__ == '__main__':
# Getting webstore URL from User
parser = argparse.ArgumentParser(description='Download CRX file from Google Chrome Webstore.')
parser.add_argument('-u', '--url', help='URL of the chrome store', required=True)
args = parser.parse_args()
downloader = ChromeAppDownloader()
try:
file_name = None
# Validating and building app ID, file name for the given URL
chrome_app_id, file_name = downloader.parse(chrome_store_url=args.url)
if chrome_app_id:
download_url = downloader.CRX_URL.replace("~~~~", chrome_app_id)
# Downloading the CRX file
extension_file = downloader.download(download_url, file_name)
# Grab downloaded .crx, strip first 307 bytes and write to zip removing crx file
f = open(extension_file, 'rb')
f.seek(307) # skip first x bytes
zipcontent = f.read()
zip_name = extension_file.replace("crx", "zip")
open(zip_name, "wb").write(zipcontent)
os.remove(extension_file)
# extract content
zip_path = zip_name.replace(".zip", "")
with zipfile.ZipFile(zip_name, 'r') as zip_ref:
zip_ref.extractall(zip_path)
except Exception as e:
print(e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment