Created
December 10, 2024 00:19
-
-
Save codeallthethingz/38e340d15b26dc0b75e455aae37df8e2 to your computer and use it in GitHub Desktop.
Take a slackdump zip file and extract all the images and recreate the slack export with your public IP and port.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
import json | |
import re | |
import shutil | |
import zipfile | |
from pathlib import Path | |
import requests | |
class IPLookupError(Exception): | |
"""Raised when external IP lookup fails""" | |
pass | |
def get_external_ip(): | |
"""Get the machine's external IP address using Amazon's checkip service""" | |
try: | |
response = requests.get("https://checkip.amazonaws.com", timeout=5) | |
if response.status_code != 200: | |
raise IPLookupError("Failed to get external IP from Amazon checkip service") | |
return response.text.strip() | |
except Exception as e: | |
raise IPLookupError(f"Failed to get external IP: {str(e)}") | |
def process_json(data, ip, port): | |
"""Process JSON content and replace file URLs with paths to extracted files""" | |
if isinstance(data, dict): | |
for key, value in data.items(): | |
if isinstance(value, (dict, list)): | |
process_json(value, ip, port) | |
elif isinstance(value, str): | |
# List of keys to update with the same URL | |
keys_to_update = [ | |
"url_private", | |
"thumb_64", | |
"url_private_download", | |
"thumb_80", | |
"thumb_160", | |
"thumb_360", | |
"thumb_360_gif", | |
"permalink", | |
"permalink_public", | |
"thumb_480", | |
"thumb_720", | |
"thumb_960", | |
"thumb_1024", | |
] | |
if key == "url_private": | |
# Get filename from url_private and make URL safe by replacing special chars | |
filename = value.split("/")[-1] | |
safe_filename = re.sub(r"[^a-zA-Z0-9.]", "_", filename) | |
# Generate new URL | |
new_url = f"http://{ip}:{port}/{safe_filename}" | |
# Update all keys with the new URL | |
for update_key in keys_to_update: | |
if update_key in data: | |
data[update_key] = new_url | |
elif isinstance(data, list): | |
for item in data: | |
if isinstance(item, (dict, list)): | |
process_json(item, ip, port) | |
def extract_attachments(zip_path, extract_dir): | |
"""Extract all attachments from the ZIP file""" | |
with zipfile.ZipFile(zip_path, "r") as zip_ref: | |
# Create test_files directory | |
test_files_dir = Path(extract_dir) | |
test_files_dir.mkdir(parents=True, exist_ok=True) | |
# Iterate through all files in the ZIP | |
for file_info in zip_ref.filelist: | |
# Look for files in attachments directories | |
if "/attachments/" in file_info.filename: | |
# Extract the file to test_files_dir | |
filename = file_info.filename | |
# Skip if it's just the attachments directory itself | |
if filename.endswith("/"): | |
continue | |
# Get just the filename without path and make URL safe | |
base_filename = Path(filename).name | |
safe_filename = re.sub(r"[^a-zA-Z0-9.]", "_", base_filename) | |
target_path = test_files_dir / safe_filename | |
source = zip_ref.open(file_info) | |
target = open(target_path, "wb") | |
shutil.copyfileobj(source, target) | |
source.close() | |
target.close() | |
return test_files_dir | |
def main(): | |
parser = argparse.ArgumentParser(description="Process Slack export ZIP file") | |
parser.add_argument("port", type=int, help="Port number to use") | |
parser.add_argument("zipfile", type=str, help="Path to Slack export ZIP file") | |
parser.add_argument( | |
"--debug", action="store_true", help="Output original and proxied JSON files" | |
) | |
args = parser.parse_args() | |
try: | |
# Get external IP address - will raise IPLookupError if it fails | |
ip = get_external_ip() | |
except IPLookupError as e: | |
print(f"Error: {str(e)}") | |
print("Cannot proceed without external IP address") | |
exit(1) | |
input_zip = args.zipfile | |
input_path = Path(input_zip) | |
output_zip = str(input_path.with_name(f"proxied_{input_path.name}")) | |
# Clean up any existing debug and test files directories | |
debug_dir = input_path.parent / "debug" | |
extract_dir = input_path.parent / f"{input_path.stem}_files" | |
if debug_dir.exists(): | |
shutil.rmtree(debug_dir) | |
if extract_dir.exists(): | |
shutil.rmtree(extract_dir) | |
# Extract attachments | |
test_files_dir = extract_attachments(input_zip, extract_dir) | |
print(f"Attachments extracted to: {test_files_dir}") | |
# Create debug directories if needed | |
if args.debug: | |
debug_dir = input_path.parent / "debug" | |
original_dir = debug_dir / "original" | |
proxied_dir = debug_dir / "swapped" | |
original_dir.mkdir(parents=True, exist_ok=True) | |
proxied_dir.mkdir(parents=True, exist_ok=True) | |
# Process the ZIP file | |
with zipfile.ZipFile(input_zip, "r") as zip_ref: | |
with zipfile.ZipFile(output_zip, "w") as new_zip: | |
for file_info in zip_ref.filelist: | |
# Skip attachments folders | |
if "/attachments/" in file_info.filename: | |
continue | |
content = zip_ref.read(file_info.filename) | |
if file_info.filename.endswith(".json"): | |
# Process JSON files | |
json_data = json.loads(content) | |
if args.debug: | |
# Save original JSON | |
original_file = original_dir / file_info.filename | |
original_file.parent.mkdir(parents=True, exist_ok=True) | |
with open(original_file, "w") as f: | |
json.dump(json_data, f, indent=2) | |
process_json(json_data, ip, args.port) | |
if args.debug: | |
# Save proxied JSON | |
proxied_file = proxied_dir / file_info.filename | |
proxied_file.parent.mkdir(parents=True, exist_ok=True) | |
with open(proxied_file, "w") as f: | |
json.dump(json_data, f, indent=2) | |
content = json.dumps(json_data).encode("utf-8") | |
# Write the file to the new ZIP | |
new_zip.writestr(file_info.filename, content) | |
print(f"Processed ZIP file saved as: {output_zip}") | |
print(f"Using IP:Port -> {ip}:{args.port}") | |
if args.debug: | |
print(f"Debug files written to: {debug_dir}") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment