Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
55538aba6a | ||
|
0d66d5b79e | ||
|
4ed01b60ae | ||
|
c8e9845954 | ||
|
2680ddca0a | ||
|
71f67b709a | ||
|
87ea90c8bf | ||
|
f7c287068e | ||
|
bc36d2bead | ||
|
b0fb6c3841 | ||
|
8fb33e9cae | ||
|
4ce583a5a9 | ||
|
2d8f137cb6 | ||
|
741ca20c35 | ||
|
453dc05611 | ||
|
2b9e711279 | ||
|
51ef51bdf9 | ||
|
6eb42c30dd | ||
|
ede4d21a68 | ||
|
cd3a832a18 | ||
|
300d688368 |
32
README.md
32
README.md
|
@ -1,11 +1,31 @@
|
||||||
|
# This Code is undergoing a rewrite and is currently not functioning correctly. Check back soon for the updated version
|
||||||
# Android-Mobile-Toolkit
|
# Android-Mobile-Toolkit
|
||||||
This is the beginning of a program to root and extract data from android devices using adb
|
This is a python based program to root and extract data from android devices using adb
|
||||||
|
|
||||||
|
A compiled version is available in the releases tab
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Automatically detect the correct version of TWRP for a plugged in device
|
+ Automatically detect the correct version of TWRP for a plugged in device
|
||||||
* Root any device that is TWRP compatible
|
+ Root any device that is TWRP compatible
|
||||||
|
+ Allows specific app data to be extracted
|
||||||
|
|
||||||
## To-Do
|
## To-Do
|
||||||
* ~~Implement a menu system~~
|
+ ~~Implement a menu system~~
|
||||||
* ~~Implement Fastboot and Magisk compatibility to root a device~~
|
+ ~~Implement Fastboot and Magisk compatibility to root a device~~
|
||||||
* Implement utilities to pull and process app data
|
+ Implement utilities to pull and process app data
|
||||||
|
+ ~~Add options to extract specific app files~~
|
||||||
|
+ Add options to extract all data on the phone
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
v1.1
|
||||||
|
+ App extraction added
|
||||||
|
+ Downloading twrp now happens without user interaction
|
||||||
|
+ Root checking option added
|
||||||
|
|
||||||
|
v1.0.1
|
||||||
|
+ Updated zip with correct files for rooting
|
||||||
|
+ Spelling fixes
|
||||||
|
|
||||||
|
v1.0
|
||||||
|
+ Initial version
|
||||||
|
+ Root any twrp compatible device
|
||||||
|
|
149
amt.py
149
amt.py
|
@ -1,126 +1,65 @@
|
||||||
#amt.py
|
# amt.py
|
||||||
"""
|
"""
|
||||||
Code to interact with an android device using ADB
|
Code to interact with an android device using ADB
|
||||||
Written by Kevin Rode
|
Written by Kevin Rode
|
||||||
Last Updated Sep 28 2019
|
|
||||||
"""
|
"""
|
||||||
import adbutils
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
from helpers import root
|
||||||
import time
|
from helpers import extract
|
||||||
import requests
|
|
||||||
from lxml import html
|
|
||||||
from pyfiglet import Figlet
|
|
||||||
def adb_start():
|
|
||||||
if "platform-tools" in os.environ['PATH']:
|
|
||||||
print("ADB found in PATH")
|
|
||||||
else:
|
|
||||||
os.environ['PATH'] += ';'+os.getcwd()+'\\platform-tools'
|
|
||||||
|
|
||||||
|
|
||||||
def adb_connect():
|
|
||||||
adb = adbutils.AdbClient(host="127.0.0.1", port=5037)
|
|
||||||
d = adb.device()
|
|
||||||
if d != None:
|
|
||||||
print("Device connected.")
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
def twrp_download(d):
|
|
||||||
found = 0
|
|
||||||
files = os.listdir(os.curdir)
|
|
||||||
for file in files:
|
|
||||||
if "twrp" in file:
|
|
||||||
found = 1
|
|
||||||
if found != 1:
|
|
||||||
cpu = d.shell('cat /proc/cpuinfo | grep Hardware')
|
|
||||||
cpu = cpu.replace(" ","")
|
|
||||||
cpu = re.sub(r'(.+:)', '', cpu)
|
|
||||||
r = requests.get('https://dl.twrp.me/'+cpu)
|
|
||||||
tree = html.fromstring(r.text)
|
|
||||||
urls = tree.xpath('//a/@href')
|
|
||||||
downloads = []
|
|
||||||
for i in urls:
|
|
||||||
if "img" in i:
|
|
||||||
downloads.append(i)
|
|
||||||
url_to_download = "https://dl.twrp.me"+downloads[0]
|
|
||||||
url_to_download = url_to_download.replace('.html', '')
|
|
||||||
print("Use this link to download twrp for your connected device: "+url_to_download)
|
|
||||||
print("Ensure that the downloaded file is moved to the same folder as the script before continuing")
|
|
||||||
input("Press Enter to continue...")
|
|
||||||
files = os.listdir(os.curdir)
|
|
||||||
for file in files:
|
|
||||||
if "twrp" in file:
|
|
||||||
found = 1
|
|
||||||
while found != 1:
|
|
||||||
print("File not found. Please confirm it has been moved to the correct directory")
|
|
||||||
input("Press Enter to continue...")
|
|
||||||
files = os.listdir(os.curdir)
|
|
||||||
for file in files:
|
|
||||||
if "twrp" in file:
|
|
||||||
found = 1
|
|
||||||
else:
|
|
||||||
print("twrp already downloaded")
|
|
||||||
|
|
||||||
|
|
||||||
def push_files(d):
|
|
||||||
initcheck_magisk = d.shell("cd /sdcard && ls | grep Magisk")
|
|
||||||
if initcheck_magisk == None and initcheck_twrp == None:
|
|
||||||
d.sync.push("Magisk-v19.3.zip", "/sdcard/Magisk.zip")
|
|
||||||
check_magisk = d.shell("cd /sdcard && ls | grep Magisk")
|
|
||||||
if check != None:
|
|
||||||
print("File copied successfully.")
|
|
||||||
else:
|
|
||||||
print("Something went wrong. Please try again.")
|
|
||||||
else:
|
|
||||||
print("Magisk already copied")
|
|
||||||
|
|
||||||
|
|
||||||
def reboot_bootloader():
|
|
||||||
adb = "platform-tools\\adb.exe"
|
|
||||||
fastboot = "platform-tools\\fastboot.exe"
|
|
||||||
os.system(adb+" reboot bootloader")
|
|
||||||
input("Press Enter when the device has rebooted")
|
|
||||||
os.system(fastboot+" devices")
|
|
||||||
|
|
||||||
|
|
||||||
def root_device():
|
|
||||||
adb = "platform-tools\\adb.exe"
|
|
||||||
fastboot = "platform-tools\\fastboot.exe"
|
|
||||||
files = os.listdir(os.curdir)
|
|
||||||
for file in files:
|
|
||||||
if "twrp" in file:
|
|
||||||
twrp = file
|
|
||||||
os.system(fastboot+ " boot "+twrp)
|
|
||||||
input("Press Enter when TWRP has booted")
|
|
||||||
print("Follow the onscreen directions to install Magisk (Located at the bottom of the install window)")
|
|
||||||
print("After Magisk installs click [Reboot] then [Do Not Install]")
|
|
||||||
input("Press Enter when the device has rebooted")
|
|
||||||
|
|
||||||
def menu():
|
def menu():
|
||||||
while True:
|
while True:
|
||||||
banner = Figlet(font='Standard')
|
print("[1] Root Device\n[2] Check root\n[3] Extract Data (WIP)\n[99] Quit")
|
||||||
print(banner.renderText('Android Mobile Toolkit'))
|
|
||||||
print("[1] Root Device (WIP)\n[2] Extract Data (Coming Soon)\n[99] Quit")
|
|
||||||
choice = input("Please select a number: ")
|
choice = input("Please select a number: ")
|
||||||
if int(choice) == 1:
|
if int(choice) == 1:
|
||||||
device = adb_connect()
|
root.root_device()
|
||||||
twrp_download(device)
|
|
||||||
push_files(device)
|
|
||||||
reboot_bootloader()
|
|
||||||
root_device()
|
|
||||||
elif int(choice) == 2:
|
elif int(choice) == 2:
|
||||||
print("Data extraction is coming soon.")
|
root.root_check()
|
||||||
time.sleep(2)
|
elif int(choice) == 3:
|
||||||
|
extract.extract_menu()
|
||||||
elif int(choice) == 99:
|
elif int(choice) == 99:
|
||||||
print("Goodbye!")
|
print("Goodbye!")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
else:
|
||||||
|
print("Unknown input")
|
||||||
|
|
||||||
|
def show_help():
|
||||||
|
print("Android Mobile Toolkit v1.1")
|
||||||
|
print("Written by Kevin Rode (kevroded)")
|
||||||
|
print()
|
||||||
|
print("Run with amt.exe [options]")
|
||||||
|
print()
|
||||||
|
print("OPTIONS:")
|
||||||
|
print(" --interactive : start the utility in a mode with a menu for the user to select options on")
|
||||||
|
print(" -i : alias for --interactive")
|
||||||
|
print(" --root : root a connected Android device")
|
||||||
|
print(" -r : alias for --root")
|
||||||
|
print(" --check-root : checks if the device is rooted")
|
||||||
|
print(" -Ae : Extract data in app extract mode. Add -o to specify an output directory")
|
||||||
|
print(" --help : print this message")
|
||||||
|
print(" -h : alias for --help")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
adb_start()
|
if "--interactive" in sys.argv[1:] or "-i" in sys.argv[1:]:
|
||||||
menu()
|
root.adb_start()
|
||||||
|
menu()
|
||||||
|
elif "--root" in sys.argv[1:] or "-r" in sys.argv[1:]:
|
||||||
|
root.root_device()
|
||||||
|
elif "--help" in sys.argv[1:] or "-h" in sys.argv[1:]:
|
||||||
|
show_help()
|
||||||
|
elif "--check-root" in sys.argv[1:]:
|
||||||
|
root.root_check()
|
||||||
|
elif "-Ae" in sys.argv[1:]:
|
||||||
|
if "-o" in sys.argv[1:]:
|
||||||
|
output_index = sys.argv.index("-o")
|
||||||
|
output = sys.argv[output_index+1]
|
||||||
|
extract.app_extract(output)
|
||||||
|
else:
|
||||||
|
extract.app_extract()
|
||||||
|
else:
|
||||||
|
show_help()
|
||||||
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
BIN
helpers/__pycache__/extract.cpython-37.pyc
Normal file
BIN
helpers/__pycache__/extract.cpython-37.pyc
Normal file
Binary file not shown.
BIN
helpers/__pycache__/root.cpython-37.pyc
Normal file
BIN
helpers/__pycache__/root.cpython-37.pyc
Normal file
Binary file not shown.
78
helpers/extract.py
Normal file
78
helpers/extract.py
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import adbutils
|
||||||
|
from helpers import root
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def recovery_boot():
|
||||||
|
adb = "platform-tools\\adb.exe"
|
||||||
|
adbcheck = os.popen(adb+" devices").read()
|
||||||
|
if "recovery" in adbcheck:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
device = root.adb_connect()
|
||||||
|
root.twrp_download(device)
|
||||||
|
root.reboot_bootloader()
|
||||||
|
adb = "platform-tools\\adb.exe"
|
||||||
|
fastboot = "platform-tools\\fastboot.exe"
|
||||||
|
files = os.listdir(os.curdir)
|
||||||
|
for file in files:
|
||||||
|
if "twrp" in file:
|
||||||
|
twrp = file
|
||||||
|
else:
|
||||||
|
twrploc = 0
|
||||||
|
while twrploc == 0:
|
||||||
|
input("TWRP not found. Please ensure it is in the correct location and press enter to continue. ")
|
||||||
|
files = os.listdir(os.curdir)
|
||||||
|
for file in files:
|
||||||
|
if "twrp" in file:
|
||||||
|
twrp = file
|
||||||
|
twrploc = 1
|
||||||
|
os.system(fastboot + " boot "+twrp)
|
||||||
|
input("Press Enter when TWRP has booted")
|
||||||
|
|
||||||
|
|
||||||
|
def list_apps():
|
||||||
|
adb = "platform-tools\\adb.exe"
|
||||||
|
apps = os.popen(adb+" shell (ls /data/data)").read()
|
||||||
|
app_array = apps.split("\n")
|
||||||
|
for i in app_array:
|
||||||
|
print(i)
|
||||||
|
|
||||||
|
|
||||||
|
def download_app(o=None):
|
||||||
|
app = input("Please enter the name of the app you would like to download: ")
|
||||||
|
adb = "platform-tools\\adb.exe"
|
||||||
|
os.system(adb+" shell (cp -R /data/data/"+app+" /sdcard/"+app+")")
|
||||||
|
if o == None:
|
||||||
|
output = input("Please enter the output directory for the app files. Leave blank to download to current directory: ")
|
||||||
|
if output != None:
|
||||||
|
os.makedirs(output)
|
||||||
|
os.system(adb+" pull /sdcard/"+app+" "+output)
|
||||||
|
else:
|
||||||
|
os.system(adb+" pull /sdcard/"+app)
|
||||||
|
else:
|
||||||
|
if os.path.isdir(o) == False:
|
||||||
|
os.makedirs(o)
|
||||||
|
os.system(adb+" pull /sdcard/"+app+" "+o)
|
||||||
|
|
||||||
|
|
||||||
|
def app_extract(output=None):
|
||||||
|
recovery_boot()
|
||||||
|
list_apps()
|
||||||
|
download_app(output)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_menu():
|
||||||
|
while True:
|
||||||
|
print("How would you like to extract data")
|
||||||
|
print("[1] App extraction\n[2] Whole Phone Extraction (via Android Backup)(COMING SOON)\n[3] Whole Phone Extraction (via adb shell)(COMING SOON)\n[99] Main Menu")
|
||||||
|
choice = input()
|
||||||
|
if int(choice) == 1:
|
||||||
|
app_extract()
|
||||||
|
elif int(choice) == 2:
|
||||||
|
print()
|
||||||
|
elif int(choice) == 3:
|
||||||
|
print()
|
||||||
|
elif int(choice) == 99:
|
||||||
|
break
|
110
helpers/root.py
Normal file
110
helpers/root.py
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import adbutils
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
import requests
|
||||||
|
from lxml import html
|
||||||
|
|
||||||
|
def adb_start():
|
||||||
|
if "platform-tools" in os.environ['PATH']:
|
||||||
|
print("ADB found in PATH")
|
||||||
|
else:
|
||||||
|
os.environ['PATH'] += ';'+os.getcwd()+'\\platform-tools'
|
||||||
|
|
||||||
|
|
||||||
|
def adb_connect():
|
||||||
|
adb = adbutils.AdbClient(host="127.0.0.1", port=5037)
|
||||||
|
d = adb.device()
|
||||||
|
if d != None:
|
||||||
|
print("Device connected.")
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def twrp_download(d):
|
||||||
|
found = 0
|
||||||
|
files = os.listdir(os.curdir)
|
||||||
|
for file in files:
|
||||||
|
if "twrp" in file:
|
||||||
|
found = 1
|
||||||
|
if found != 1:
|
||||||
|
cpu = d.shell('getprop ro.product.board')
|
||||||
|
r = requests.get('https://dl.twrp.me/'+cpu)
|
||||||
|
tree = html.fromstring(r.text)
|
||||||
|
urls = tree.xpath('//a/@href')
|
||||||
|
downloads = []
|
||||||
|
for i in urls:
|
||||||
|
if "img" in i:
|
||||||
|
downloads.append(i)
|
||||||
|
url_to_download = "https://dl.twrp.me"+downloads[0]
|
||||||
|
url_to_download = url_to_download.replace('.html', '')
|
||||||
|
s = requests.Session()
|
||||||
|
s.headers.update({'referer':url_to_download})
|
||||||
|
img = s.get(url_to_download)
|
||||||
|
with open("twrp.img",'wb') as f:
|
||||||
|
f.write(img.content)
|
||||||
|
files = os.listdir(os.curdir)
|
||||||
|
for file in files:
|
||||||
|
if "twrp" in file:
|
||||||
|
found = 1
|
||||||
|
while found != 1:
|
||||||
|
print("File not found. Please confirm it has been moved to the correct directory")
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
files = os.listdir(os.curdir)
|
||||||
|
for file in files:
|
||||||
|
if "twrp" in file:
|
||||||
|
found = 1
|
||||||
|
else:
|
||||||
|
print("Error. Returning to the main menu")
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("twrp already downloaded")
|
||||||
|
|
||||||
|
|
||||||
|
def push_files(d):
|
||||||
|
initcheck_magisk = d.shell("cd /sdcard && ls | grep Magisk")
|
||||||
|
if initcheck_magisk == None and initcheck_twrp == None:
|
||||||
|
d.sync.push("Magisk-v19.3.zip", "/sdcard/Magisk.zip")
|
||||||
|
check_magisk = d.shell("cd /sdcard && ls | grep Magisk")
|
||||||
|
if check != None:
|
||||||
|
print("File copied successfully.")
|
||||||
|
else:
|
||||||
|
print("Something went wrong. Please try again.")
|
||||||
|
else:
|
||||||
|
print("Magisk already copied")
|
||||||
|
|
||||||
|
|
||||||
|
def reboot_bootloader():
|
||||||
|
adb = "platform-tools\\adb.exe"
|
||||||
|
fastboot = "platform-tools\\fastboot.exe"
|
||||||
|
os.system(adb+" reboot bootloader")
|
||||||
|
input("Press Enter when the device has rebooted")
|
||||||
|
os.system(fastboot+" devices")
|
||||||
|
|
||||||
|
|
||||||
|
def root_device():
|
||||||
|
device = adb_connect()
|
||||||
|
twrp_download(device)
|
||||||
|
push_files(device)
|
||||||
|
reboot_bootloader()
|
||||||
|
adb = "platform-tools\\adb.exe"
|
||||||
|
fastboot = "platform-tools\\fastboot.exe"
|
||||||
|
files = os.listdir(os.curdir)
|
||||||
|
for file in files:
|
||||||
|
if "twrp" in file:
|
||||||
|
twrp = file
|
||||||
|
os.system(fastboot + " boot "+twrp)
|
||||||
|
input("Press Enter when TWRP has booted")
|
||||||
|
print("Follow the onscreen directions to install Magisk (Located at the bottom of the install window)")
|
||||||
|
print("After Magisk installs click [Reboot] then [Do Not Install]")
|
||||||
|
input("Press Enter when the device has rebooted")
|
||||||
|
|
||||||
|
|
||||||
|
def root_check():
|
||||||
|
device = adb_connect()
|
||||||
|
rootcheck = device.shell("ls /sbin | grep su")
|
||||||
|
if rootcheck != None:
|
||||||
|
print("Device is rooted")
|
||||||
|
else:
|
||||||
|
print("Device is not rooted")
|
|
@ -3539,32 +3539,14 @@
|
||||||
"integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4="
|
"integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4="
|
||||||
},
|
},
|
||||||
"handlebars": {
|
"handlebars": {
|
||||||
"version": "4.1.2",
|
"version": "4.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
|
||||||
"integrity": "sha1-trN8HO0DBrIh4JT8eso+wjsTG2c=",
|
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"neo-async": "^2.6.0",
|
"neo-async": "^2.6.0",
|
||||||
"optimist": "^0.6.1",
|
"optimist": "^0.6.1",
|
||||||
"source-map": "^0.6.1",
|
"source-map": "^0.6.1",
|
||||||
"uglify-js": "^3.1.4"
|
"uglify-js": "^3.1.4"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"commander": {
|
|
||||||
"version": "2.20.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
|
||||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"uglify-js": {
|
|
||||||
"version": "3.5.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.9.tgz",
|
|
||||||
"integrity": "sha512-WpT0RqsDtAWPNJK955DEnb6xjymR8Fn0OlK4TT4pS0ASYsVPqr5ELhgwOwLCP5J5vHeJ4xmMmz3DEgdqC10JeQ==",
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"commander": "~2.20.0",
|
|
||||||
"source-map": "~0.6.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"has": {
|
"has": {
|
||||||
|
@ -5688,7 +5670,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6643,6 +6625,24 @@
|
||||||
"source-map": "~0.6.1"
|
"source-map": "~0.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"uglify-js": {
|
||||||
|
"version": "3.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.3.tgz",
|
||||||
|
"integrity": "sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"commander": "~2.20.3",
|
||||||
|
"source-map": "~0.6.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"commander": {
|
||||||
|
"version": "2.20.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"uglifyjs-webpack-plugin": {
|
"uglifyjs-webpack-plugin": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz",
|
||||||
|
|
Reference in New Issue
Block a user