💾 Archived View for tilde.team › ~jahoti › massgov.py captured on 2024-06-16 at 13:29:41.
⬅️ 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') ))))