Files
smart-city-digital-twin-mar…/configuration/ditto/modify-jar.py

170 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""
Modify the reference.conf inside the Ditto gateway JAR.
Inserts ditto { gateway { authentication { pre-authentication { enabled = true } } } }
at the root level, before the final closing brace.
"""
import zipfile
import shutil
import os
import subprocess
import sys
JAR_PATH = "/tmp/ditto-jar-mod/ditto-gateway-service-3.8.12-allinone.jar"
AUTH_BLOCK = """
### Custom Ditto auth override - pre-authentication enabled
ditto {
gateway {
authentication {
pre-authentication {
enabled = true
}
devops {
secured = false
devops-authentication-method = "basic"
password = "ditto-devops-secret"
status-secured = false
status-authentication-method = "basic"
statusPassword = "ditto-status-secret"
}
}
}
}
"""
def main():
os.makedirs("/tmp/ditto-jar-mod", exist_ok=True)
print("=== Step 1: Extracting JAR ===")
result = subprocess.run(
["docker", "run", "--rm", "eclipse/ditto-gateway:latest",
"cat", "/opt/ditto/ditto-gateway-service-3.8.12-allinone.jar"],
capture_output=True, check=True
)
with open(JAR_PATH, "wb") as f:
f.write(result.stdout)
print(f"JAR: {len(result.stdout)} bytes")
print("=== Step 2: Modifying reference.conf ===")
with zipfile.ZipFile(JAR_PATH, 'r') as zin:
ref_conf = zin.read("reference.conf").decode("utf-8")
lines = ref_conf.split('\n')
total_lines = len(lines)
print(f"reference.conf: {total_lines} lines")
# Find the LAST closing brace at root level (depth 0)
# Track depth through the entire file
depth = 0
last_root_close_idx = None
for i, line in enumerate(lines):
stripped = line.strip()
if not stripped or stripped.startswith('#'):
continue
# Count braces (simple approach - count { and })
# This isn't perfect for HOCON but works for our case
for ch in stripped:
if ch == '{':
depth += 1
elif ch == '}':
depth -= 1
if depth == 0:
last_root_close_idx = i
if last_root_close_idx is None:
print("ERROR: Could not find root-level closing brace!")
sys.exit(1)
insert_idx = last_root_close_idx
print(f"Last root-level '}}' at line {insert_idx + 1}: '{lines[insert_idx].strip()}'")
# Check if we need a comma before our block
# Look at the non-empty line before insert_idx
prev_idx = insert_idx - 1
while prev_idx >= 0 and lines[prev_idx].strip() == '':
prev_idx -= 1
if prev_idx >= 0:
prev_stripped = lines[prev_idx].strip()
if prev_stripped.endswith('}'):
# Need to add a comma
lines[prev_idx] = lines[prev_idx].rstrip()
if not lines[prev_idx].endswith(','):
lines[prev_idx] += ','
print(f"Added comma to line {prev_idx + 1}")
# Insert our block
auth_lines = AUTH_BLOCK.split('\n')
new_lines = lines[:insert_idx] + auth_lines + lines[insert_idx:]
modified_conf = '\n'.join(new_lines)
print(f"Modified: {total_lines} -> {len(new_lines)} lines")
# Verify brace balance
depth = 0
for i, line in enumerate(new_lines):
stripped = line.strip()
if not stripped or stripped.startswith('#'):
continue
for ch in stripped:
if ch == '{':
depth += 1
elif ch == '}':
depth -= 1
if depth < 0:
print(f"ERROR: Negative depth at line {i+1}")
sys.exit(1)
print(f"Brace depth check: {depth} (should be 0)")
if depth != 0:
print("ERROR: Unbalanced braces!")
sys.exit(1)
# Verify ditto is at root level
for i, line in enumerate(new_lines):
if line.strip() == 'ditto {':
indent = len(line) - len(line.lstrip())
print(f"'ditto {{' at line {i+1}, indent: {indent}")
if indent != 0:
print(f"WARNING: Expected indent 0, got {indent}")
break
print("=== Step 3: Creating unsigned JAR ===")
skip_files = set()
with zipfile.ZipFile(JAR_PATH, 'r') as zin:
for name in zin.namelist():
if name.startswith("META-INF/"):
upper = name.upper()
if upper.endswith(".SF") or upper.endswith(".RSA") or upper.endswith(".DSA") or upper == "MANIFEST.MF":
skip_files.add(name)
with zipfile.ZipFile(JAR_PATH + ".new", 'w', zipfile.ZIP_DEFLATED) as zout:
for item in zin.infolist():
if item.filename in skip_files:
continue
data = zin.read(item.filename)
if item.filename == "reference.conf":
data = modified_conf.encode("utf-8")
info = zipfile.ZipInfo(filename=item.filename, date_time=item.date_time)
info.compress_type = zipfile.ZIP_DEFLATED
info.external_attr = item.external_attr
zout.writestr(info, data)
shutil.move(JAR_PATH + ".new", JAR_PATH)
print("=== Step 4: Verifying ===")
with zipfile.ZipFile(JAR_PATH, 'r') as z:
ref = z.read("reference.conf").decode("utf-8")
assert "pre-authentication" in ref
sig = [n for n in z.namelist() if n.startswith("META-INF/") and n.upper().endswith(('.SF', '.RSA', '.DSA'))]
print(f"OK Signature files: {len(sig)}")
print(f"OK JAR size: {os.path.getsize(JAR_PATH)}")
print("\n=== DONE ===")
if __name__ == "__main__":
main()