import secrets
import socket
import struct
import sys


def read_line(conn):
    data = bytearray()
    while not data.endswith(b"\n"):
        part = conn.recv(1)
        if not part:
            raise ConnectionError("client disconnected")
        data.extend(part)
    return bytes(data[:-1])


def handle(conn):
    base = 0x555500000000 + (secrets.randbelow(0x10000) << 12)
    conn.sendall(b"Night Shift\nname: ")
    name = read_line(conn)
    rendered = name.replace(b"%7$p", hex(base + 0x1540).encode())
    conn.sendall(b"hello " + rendered + b"\n")
    conn.sendall(b"note: ")
    note = read_line(conn)
    if len(note) >= 88:
        target = struct.unpack("<Q", note[80:88])[0]
        if target == base + 0x12b0:
            conn.sendall(b"flag{night_shift_training}\n")
            return
    conn.sendall(b"note saved\n")


def serve(host, port):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listener:
        listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        listener.bind((host, port))
        listener.listen()
        print("listening on", listener.getsockname(), flush=True)
        while True:
            conn, _ = listener.accept()
            with conn:
                try:
                    handle(conn)
                except ConnectionError:
                    pass


if __name__ == "__main__":
    host = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 31340
    serve(host, port)
