#!/usr/bin/env python3
import sys, re, urllib.request, urllib.parse, http.cookiejar
from html.parser import HTMLParser

SITE="https://admin.alwaysdata.com/site/1072866/"
UA="Mozilla/5.0 (X11; Linux x86_64) curl"
COOKIE=open("/tmp/cj_A.txt").read()

# parse netscape cookie jar
cj=http.cookiejar.MozillaCookieJar("/tmp/cj_A.txt")
cj.load(ignore_discard=True, ignore_expires=True)
opener=urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj), urllib.request.HTTPRedirectHandler())

def get(url):
    req=urllib.request.Request(url, headers={"User-Agent":UA})
    with opener.open(req, timeout=30) as r:
        return r.status, r.read().decode("utf-8","replace")

URL_VAL=sys.argv[1] if len(sys.argv)>1 else "http://REPLACE/"
# fetch reverse_proxy-rendered edit form
st, html = get(SITE+"?_field_type=reverse_proxy")
print("GET edit?_field_type=reverse_proxy ->", st, "| has name=\"url\":", ('name="url"' in html))

# isolate main form: the <form method="post"> without action
# find the form start that is not object-choice and not search
starts=[m.start() for m in re.finditer(r'<form[^>]*method="post"[^>]*>', html)]
main_start=None
for s in starts:
    tag=html[s:html.find(">",s)+1]
    if 'action="/site/"' in tag or 'object-choice' in tag or 'form-search' in tag:
        continue
    main_start=s; break
end=html.find("</form>", main_start)
form=html[main_start:end]
print("main form len", len(form), "| url field in main form:", 'name="url"' in form)

class F(HTMLParser):
    def __init__(s):
        super().__init__(); s.fields=[]; s.cur_sel=None; s.sel_name=None; s.sel_options=[]; s.in_ta=False; s.ta_name=None; s.ta_val=""
    def handle_starttag(s,t,a):
        d=dict(a)
        if t=="input":
            n=d.get("name")
            if not n: return
            typ=(d.get("type") or "text").lower()
            if typ in ("checkbox","radio"):
                if "checked" in d: s.fields.append((n,d.get("value","on")))
            elif typ=="submit":
                s.fields.append((n,d.get("value","")))
            else:
                s.fields.append((n,d.get("value","")))
        elif t=="select":
            s.sel_name=d.get("name"); s.sel_options=[]; s.cur_sel=None
        elif t=="option" and s.sel_name is not None:
            s._opt_val=d.get("value",""); s._opt_sel=("selected" in d)
            if s._opt_sel: s.cur_sel=s._opt_val
        elif t=="textarea":
            s.in_ta=True; s.ta_name=d.get("name"); s.ta_val=""
    def handle_endtag(s,t):
        if t=="select" and s.sel_name is not None:
            v=s.cur_sel if s.cur_sel is not None else (s.sel_options[0] if s.sel_options else "")
            s.fields.append((s.sel_name, v)); s.sel_name=None
        elif t=="textarea" and s.in_ta:
            s.fields.append((s.ta_name, s.ta_val)); s.in_ta=False; s.ta_name=None
    def handle_data(s,data):
        if s.in_ta: s.ta_val+=data
p=F(); p.feed(form)
fields=p.fields
# override type + url + drop empty submit? include submit
d={}
order=[]
for n,v in fields:
    order.append(n)
d_list=[]
for n,v in fields:
    d_list.append([n,v])
# set type + url
def setf(name,val):
    for pair in d_list:
        if pair[0]==name:
            pair[1]=val; return
    d_list.append([name,val])
setf("type","reverse_proxy")
setf("url",URL_VAL)
# ensure httpd present
print("=== fields being submitted (name=value) ===")
for n,v in d_list:
    vv=v if len(v)<40 else v[:37]+"..."
    print(f"  {n} = {vv}")
data=urllib.parse.urlencode([(n,(v if v is not None else "")) for n,v in d_list]).encode()
req=urllib.request.Request(SITE, data=data, headers={"User-Agent":UA,
    "Referer":SITE,"Origin":"https://admin.alwaysdata.com",
    "Content-Type":"application/x-www-form-urlencoded"})
try:
    with opener.open(req, timeout=40) as r:
        st=r.status; body=r.read().decode("utf-8","replace"); final=r.geturl()
except urllib.error.HTTPError as e:
    st=e.code; body=e.read().decode("utf-8","replace"); final=SITE
print("POST save ->", st, "final:", final)
# look for errors
errs=re.findall(r'<[^>]*(?:error|invalid|alert-danger|help-block)[^>]*>([^<]{2,120})', body)
for e in errs[:15]:
    e=e.strip()
    if e: print("  msg:", e)
# check if url field error
for m in re.findall(r'(This field is required|Enter a valid URL|not allowed|forbidden|internal|invalid|private|blocked)[^<]{0,80}', body, re.I):
    print("  URLERR:", m)
