Skip to content

Instantly share code, notes, and snippets.

@codeallthethingz
Created December 10, 2024 00:19
Show Gist options
  • Save codeallthethingz/38e340d15b26dc0b75e455aae37df8e2 to your computer and use it in GitHub Desktop.
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.
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