💾 Archived View for tilde.team › ~jahoti › massgov.py captured on 2023-09-08 at 17:33:39.

View Raw

More Information

⬅️ Previous capture (2021-12-03)

-=-=-=-=-=-=-

#!/usr/bin/env python3

# A script to make a submission to the Massachusetts governor's office, released under the Apache License 2.0
# Copyright © 2020 jahoti (jahoti@ctrl-c.club)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# USER NOTES:
#    The script will ask for a phone number. Enter this as 10 digits, without any spaces, parentheses, dashes, etc.
#    The message to send should be in a file, the path to which the script then prompts for at the end.
#    A path relative to the working directory or an absolute one are both OK.

import random
from urllib.request import *

# Categories user requests could be in (from the form itself)
cats = ('Travel Guidance', 'Reporting a Business or Gathering', 'School Guidance & Childcare Assistance', 'Unemployment Assistance', 'COVID-19 Testing Options', 'COVID-19 Health Care & Insurance', 'Food Assistance Related to COVID-19', 'COVID-19 Housing Resources & Information', 'Phased Reopening', 'Request a citation', 'Other')

# Generate a random 16-character nonce for the form and multipart/form-data boundary
chars, picker = '0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM', random.Random()
nonce, boundary = ''.join([picker.choice(chars) for i in range(16)]), ''.join([picker.choice(chars) for i in range(16)])

# These fields are validated with while loops (or might not be gotten from the user in the case of "reason"), so set defaults
body = email = phnum = zip_code = reason = char = ''

# Collect user data

first_name, last_name, state = input('First Name > '), input('Last Name > '), input('State > ')

while len(zip_code) != 5 or not zip_code.isdigit(): # ZIP codes must be 5-digit sequences
	zip_code = input('ZIP Code > ')

city, address1, address2 = input('City > '), input('Address (Line 1) > '), input('Address (Line 2) (OPTIONAL) > ')

while len(phnum) != 10 or not phnum.isdigit(): # Take phone numbers as simple 10-digit sequences to make them easy to check, but...
	phnum = input('Phone Number > ')

phnum = '('+phnum[:3]+') '+phnum[3:6]+'-'+phnum[6:] # The form demands phone numbers be (XXX) XXX-XXXX, so let's format the number correctly

while True:
	email = input('E-Mail > ')
	segs = email.split('@')
	if len(segs) == 2 and segs[0] and '.' in segs[1]: # Enforce e-mails of the form *@*.* at least
		break

while char not in ('r', 's'): # Use single-character input to determine whether this is a request or statement
	char = input('(R)equest for Help or (S)tatement? > ').lower()

mail_type = 'Problem I need help with' if char == 'r' else 'Comment'

while char > 'k' or char < 'a': # Use single-character input to get which category this request belongs to (see "cats" above)
	for i, cat in enumerate(cats):
		print(chr(65+i)+'. '+cat)
	
	char = input('Topic (Choose from the Above) > ').lower()

cat = cats[ord(char)-97]

if cat == 'Other':
	reason = input('Subject (OPTIONAL) > ')

msg_file = input('Path to the message file > ')
with open(msg_file, mode='r', encoding='utf-8') as f:
	data = f.read()


#Build and post the multipart/form-data request body
for field, value in (
			('form', '1744869'), ('viewkey', 'BHDWKhhueM'), ('_submit', '1'), ('viewparam', '524744'), ('field49751862', first_name),
			('field49751877', last_name), ('field49751885', address1), ('field49751887', address2), ('field49751935', city),
			('field49751937', state), ('field49752148', zip_code), ('field49751979', phnum), ('field49752019', email),
			('field90831234', mail_type), ('field90831245', cat), ('field49751965', reason), ('field49752026', data), ('nonce', nonce)
	):
	body += '--'+boundary+'\r\nContent-Disposition: form-data; name="'+field+'"\r\n\r\n'+value+'\r\n'

request = Request('https://massgov.formstack.com/forms/index.php', method='POST',\
			headers={'content-type': 'multipart/form-data; boundary='+boundary})

request.data = (body+'--'+boundary+'--\r\n').encode('utf-8') # The body needs to be binary
with urlopen(request) as obj:
	body = obj.read()

#Remove tags, stylesheets, scripts and blank lines from the HTML response and print it
segs = body.decode('utf-8').split('<')
text = segs.pop(0)
for seg in segs:
	if not (seg.startswith(' ') or seg.startswith('script') or seg.startswith('style')):
		text += seg.split('>', maxsplit=1)[1]

print('-----------------\n')
print('\n'.join(filter(None, ( line.lstrip() for line in text.split('\n') ))))