Last active
August 9, 2024 10:12
-
-
Save zTrix/135740a8709cbca461e6 to your computer and use it in GitHub Desktop.
A simple script to check US Visa state
This file contains hidden or 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
#!/usr/bin/env python2 | |
import os, sys, datetime, re, urllib, httplib, time | |
reload(sys) | |
sys.setdefaultencoding('utf8') | |
if not sys.stdout.isatty(): | |
import codecs | |
sys.stdout = codecs.getwriter('utf8')(sys.stdout) | |
sys.stderr = codecs.getwriter('utf8')(sys.stderr) | |
import requests | |
requests.packages.urllib3.disable_warnings() | |
try: | |
from termcolor import colored | |
except: | |
ATTRIBUTES = dict( list(zip([ 'bold', 'dark', '', 'underline', 'blink', '', 'reverse', 'concealed' ], list(range(1, 9))))) | |
del ATTRIBUTES[''] | |
HIGHLIGHTS = dict( list(zip([ 'on_grey', 'on_red', 'on_green', 'on_yellow', 'on_blue', 'on_magenta', 'on_cyan', 'on_white' ], list(range(40, 48))))) | |
COLORS = dict(list(zip(['grey', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', ], list(range(30, 38))))) | |
RESET = '\033[0m' | |
def colored(text, color=None, on_color=None, attrs=None): | |
fmt_str = '\033[%dm%s' | |
if color is not None: text = fmt_str % (COLORS[color], text) | |
if on_color is not None: text = fmt_str % (HIGHLIGHTS[on_color], text) | |
if attrs is not None: | |
for attr in attrs: | |
text = fmt_str % (ATTRIBUTES[attr], text) | |
text += RESET | |
return text | |
def log(s, color = None, on_color = None, attrs = None, new_line = True, timestamp = True, f = sys.stderr): | |
if timestamp is True: | |
now = datetime.datetime.now().strftime('[%Y-%m-%d_%H:%M:%S]') | |
elif timestamp is False: | |
now = None | |
elif timestamp: | |
now = timestamp | |
if not color: | |
s = str(s) | |
else: | |
s = colored(str(s), color, on_color, attrs) | |
if now: | |
f.write(now) | |
f.write(' ') | |
f.write(s) | |
if new_line: | |
f.write('\n') | |
f.flush() | |
def visa_niv_status(location, application_id): | |
if not location or not application_id: | |
return None, None, None | |
target_url = 'https://ceac.state.gov/CEACStatTracker/Status.aspx' | |
log('[ II ] looking up visa status for %s %s' % (location, application_id)) | |
headers = { | |
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36', | |
'Cookie': 'ASP.NET_SessionId=mxrhq2454x2cwgueyvmoikqu; ceac.state.gov=1888921792.20480.0000', | |
'Origin': 'https://ceac.state.gov', | |
'Referer': 'https://ceac.state.gov/CEACStatTracker/Status.aspx', | |
'Pragma': 'no-cache', | |
} | |
session = requests.Session() | |
r = session.get(target_url, headers=headers, verify=False) | |
log('[ II ] [ %s ] %s - %d %s, %d bytes in %fs' % (r.request.method, r.url, r.status_code, r.reason, len(r.text), r.elapsed.total_seconds())) | |
viewstate_m = re.compile('<input\s+type="hidden"\s+name="__VIEWSTATE"\s+id="__VIEWSTATE"\s+value="([a-z0-9/=+:]+)"\s*/>', re.I).search(r.text) | |
viewstate = '' | |
if viewstate_m: | |
viewstate = viewstate_m.group(1) | |
valid_m = re.compile('<input\s+type="hidden"\s+name="__EVENTVALIDATION"\s+id="__EVENTVALIDATION"\s+value="([a-z0-9/=+:]+)"\s*/>', re.I).search(r.text) | |
valid = '' | |
if valid_m: | |
valid = valid_m.group(1) | |
if not valid or not viewstate: | |
log('[ EE ] cannot extract viewstate or valid: viewstate = %r, valid = %r' % (viewstate, valid), 'red') | |
return None, None, None | |
param = urllib.urlencode({ | |
'ctl00$ContentPlaceHolder1$ddlApplications': 'NIV', | |
'__ASYNCPOST': 'true', | |
'ctl00_ToolkitScriptManager1_HiddenField': ';;AjaxControlToolkit, Version=3.5.51116.0, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e:en-US:2a06c7e2-728e-4b15-83d6-9b269fb7261e:de1feab2:f2c8e708:8613aea7:f9cec9bc:3202a5a2:a67c2700:720a52bf:589eaa30:ab09e3fe:87104b7c:be6fb298;', | |
'ctl00$ToolkitScriptManager1': 'ctl00$ContentPlaceHolder1$UpdatePanel1|ctl00$ContentPlaceHolder1$btnSubmit', | |
'ctl00$ContentPlaceHolder1$btnSubmit.x': 75, | |
'ctl00$ContentPlaceHolder1$btnSubmit.y': 67, | |
'__EVENTTARGET': 'ctl00$ContentPlaceHolder1$ddlApplications', | |
'ctl00$ContentPlaceHolder1$txbCase': '', | |
'__VIEWSTATE': viewstate, | |
'__EVENTVALIDATION': valid, | |
'__EVENTARGUMENT': '', | |
'__LASTFOCUS': '', | |
}) | |
headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8' | |
headers['X-MicrosoftAjax:Delta'] = 'true' | |
headers['X-Requested-With'] = 'XMLHttpRequest' | |
r = session.post(target_url, data=param, headers=headers, verify=False) | |
log('[ II ] [ %s ] %s - %d %s, %d bytes in %fs' % (r.request.method, r.url, r.status_code, r.reason, len(r.text), r.elapsed.total_seconds())) | |
viewstate_m = re.compile(r'\|__VIEWSTATE\|([a-z0-9/=+]+)\|', re.I).search(r.text) | |
viewstate = '' | |
if viewstate_m: | |
viewstate = viewstate_m.group(1) | |
valid_m = re.compile(r'\|__EVENTVALIDATION\|([a-z0-9/=+]+)\|', re.I).search(r.text) | |
valid = '' | |
if valid_m: | |
valid = valid_m.group(1) | |
if not valid or not viewstate: | |
log('[ EE ] cannot extract viewstate or valid: viewstate = %r, valid = %r' % (viewstate, valid), 'red') | |
return None, None, None | |
param = urllib.urlencode({ | |
'ctl00$ContentPlaceHolder1$ddlApplications': 'NIV', | |
'ctl00$ContentPlaceHolder1$ddlLocation': location, | |
'ctl00$ContentPlaceHolder1$txbCase': application_id, | |
'__ASYNCPOST': 'true', | |
'ctl00_ToolkitScriptManager1_HiddenField': ';;AjaxControlToolkit, Version=3.5.51116.0, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e:en-US:2a06c7e2-728e-4b15-83d6-9b269fb7261e:de1feab2:f2c8e708:8613aea7:f9cec9bc:3202a5a2:a67c2700:720a52bf:589eaa30:ab09e3fe:87104b7c:be6fb298;', | |
'ctl00$ToolkitScriptManager1': 'ctl00$ContentPlaceHolder1$UpdatePanel1|ctl00$ContentPlaceHolder1$btnSubmit', | |
'ctl00$ContentPlaceHolder1$btnSubmit.x': 99, | |
'ctl00$ContentPlaceHolder1$btnSubmit.y': 9, | |
'__EVENTTARGET': '', | |
'__EVENTARGUMENT': '', | |
'__LASTFOCUS': '', | |
'__VIEWSTATE': viewstate, | |
'__EVENTVALIDATION': valid | |
}) | |
r = session.post(target_url, data=param, headers=headers, verify=False) | |
log('[ II ] [ %s ] %s - %d %s, %d bytes in %fs' % (r.request.method, r.url, r.status_code, r.reason, len(r.text), r.elapsed.total_seconds())) | |
pivot_m = re.compile(r'<span\s+id="ctl00_ContentPlaceHolder1_ucApplicationStatusView_lblStatus">([-a-z0-9_+\s=:]+)</span>', re.I).search(r.text) | |
pivot = '' | |
if pivot_m: | |
pivot = pivot_m.group(1) | |
update_m = re.compile(r'<span\s+id="ctl00_ContentPlaceHolder1_ucApplicationStatusView_lblStatusDate">([-a-z0-9_+\s=:]+)</span>', re.I).search(r.text) | |
update_date = '' | |
if update_m: | |
update_date = update_m.group(1) | |
case_m = re.compile(r'<span\s+id="ctl00_ContentPlaceHolder1_ucApplicationStatusView_lblCaseNo"\s+class="case-number">\s*([-a-z0-9_+=/:]+)\s*</span>', re.I).search(r.text) | |
case = '' | |
if case_m: | |
case = case_m.group(1) | |
return case, update_date, pivot | |
def passport_status(passport): | |
log('[ II ] looking up passport status: %s' % (passport)) | |
headers = { | |
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36', | |
'Origin': 'http://cgifederal.force.com', | |
'Referer': 'http://cgifederal.force.com/passporttracker?country=China&language=zh_CN', | |
'Host': 'cgifederal.force.com', | |
} | |
session = requests.Session() | |
viewstate = '' | |
mac = '' | |
version = '' | |
for x in range(3): | |
r = session.get('http://cgifederal.force.com/passporttracker?country=China&language=en', headers=headers) | |
log('[ II ] [ %s ] %s - %d %s, %d bytes in %fs' % (r.request.method, r.url, r.status_code, r.reason, len(r.text), r.elapsed.total_seconds())) | |
viewstate_m = re.compile(r'<input\s+type="hidden"\s+id="com\.salesforce\.visualforce\.ViewState"\s+name="com\.salesforce\.visualforce\.ViewState"\s+value="\s*([-a-z0-9_+=/:]+)\s*"\s*/?>', re.I).search(r.text) | |
if viewstate_m: | |
viewstate = viewstate_m.group(1) | |
mac_m = re.compile(r'<input\s+type="hidden"\s+id="com\.salesforce\.visualforce\.ViewStateMAC"\s+name="com\.salesforce\.visualforce\.ViewStateMAC"\s+value="([-a-z0-9_+=/:]+)"\s*/?>', re.I).search(r.text) | |
if mac_m: | |
mac = mac_m.group(1) | |
version_m = re.compile(r'<input\s+type="hidden"\s+id="com\.salesforce\.visualforce\.ViewStateVersion"\s+name="com\.salesforce\.visualforce\.ViewStateVersion"\s+value="([-a-z0-9_+=/:]+)"\s*/?>', re.I).search(r.text) | |
if version_m: | |
version = version_m.group(1) | |
if viewstate and mac and version: | |
break | |
else: | |
log('[ II ] viewstate or mac not found, retrying...') | |
time.sleep(1 << x) | |
if not viewstate or not mac or not version: | |
log('[ EE ] cannot extract viewstate or viewstatemac: viewstate = %r, mac = %r, version = %r' % (viewstate, mac, version), 'red') | |
return None | |
param = urllib.urlencode({ | |
'AJAXREQUEST': '_viewRoot', | |
'passportTrackerPage:psptTrackerForm': 'passportTrackerPage:psptTrackerForm', | |
'passportTrackerPage:psptTrackerForm:j_id34:j_id35:passportNo': passport, | |
'passportTrackerPage:psptTrackerForm:trackButton': 'passportTrackerPage:psptTrackerForm:trackButton', | |
'com.salesforce.visualforce.ViewState': viewstate, | |
'com.salesforce.visualforce.ViewStateMAC': mac, | |
'com.salesforce.visualforce.ViewStateVersion': version, | |
}) | |
headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8' | |
headers['X-MicrosoftAjax:Delta'] = 'true' | |
headers['X-Requested-With'] = 'XMLHttpRequest' | |
r = session.post('http://cgifederal.force.com/passporttracker', data=param, headers=headers) | |
log('[ II ] [ %s ] %s - %d %s, %d bytes in %fs' % (r.request.method, r.url, r.status_code, r.reason, len(r.text), r.elapsed.total_seconds())) | |
result_m = re.compile(r'<span\s+class="result">([^<>]+)</span>', re.I).search(r.text) | |
result = '' | |
if result_m: | |
result = result_m.group(1) | |
return result | |
if __name__ == '__main__': | |
if len(sys.argv) < 2: | |
print 'usage: %s <location> <application_id> <passport>' % sys.argv[0] | |
print 'usage: %s <location> <application_id>' % sys.argv[0] | |
print 'usage: %s <passport>' % sys.argv[0] | |
print '' | |
print 'example:' | |
print ' # BEJ for beijing' | |
print ' $ %s BEJ AA01234T8S G12345678' % sys.argv[0] | |
print ' # GUZ for guangzhou' | |
print ' $ %s GUZ AA01234T8S' % sys.argv[0] | |
print ' $ %s G12345678' % sys.argv[0] | |
sys.exit(10) | |
if len(sys.argv) >= 4: | |
location = sys.argv[1] | |
app_id = sys.argv[2] | |
passport = sys.argv[3] | |
caseid, update_date, state = visa_niv_status(location, app_id) | |
print caseid, update_date, state | |
print passport_status(passport) | |
elif len(sys.argv) == 3: | |
location = sys.argv[1] | |
app_id = sys.argv[2] | |
caseid, update_date, state = visa_niv_status(location, app_id) | |
print caseid, update_date, state | |
elif len(sys.argv) == 2: | |
passport = sys.argv[1] | |
print passport_status(passport) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment