def test_a_confusing_case(client, msend): """ Final boss. """ prepare() try: _, uf = create_user_and_form(client) DB.session.add( Form(email=uf.email, confirmed=False, host="example.com")) DB.session.add( Form(email=uf.email, confirmed=True, host="example.com/contact")) DB.session.add( Form(email=uf.email, confirmed=True, host="www.example.com/")) DB.session.commit() assert Form.query.count() == 4 form = Form.get_with(email=uf.email, host="example.com/") assert form assert form.confirmed assert form.host == "www.example.com/" form2 = Form.get_with(email=uf.email, host="www.example.com") assert form2 assert form2.confirmed assert form.host == "www.example.com/" contact = form.get_with(email=uf.email, host="www.example.com/contact/") assert contact assert contact.host == "example.com/contact" assert form.id != contact.id assert form.id == form2.id r = client.post( "/" + uf.email, headers={"Referer": "http://example.com/"}, data={"name": "example"}, ) assert r.status_code == 302 assert "next" in r.location r = client.post( "/" + uf.email, headers={"Referer": "www.example.com"}, data={"name": "example"}, ) assert r.status_code == 302 assert "next" in r.location assert msend.call_count == 2 assert Form.query.count() == 4 form3 = Form.get_with(email=uf.email, host="example.com") assert 2 == form.submissions.count() assert form3.id == form2.id == form.id finally: revert()
def test_unconfirm_process(client, msend): # confirm some forms for the same email address f1 = Form('*****@*****.**', 'testwebsite.com') f1.confirmed = True DB.session.add(f1) f2 = Form('*****@*****.**', 'othertestwebsite.com') f2.confirmed = True DB.session.add(f2) f3 = Form('*****@*****.**', 'anothertestwebsite.com') f3.confirmed = True DB.session.add(f3) DB.session.commit() # try a submission r = client.post('/[email protected]', headers={'Referer': 'http://testwebsite.com'}, data={'name': 'carol'}) assert msend.called request_unconfirm_url = url_for('request_unconfirm_form', form_id=f1.id, _external=True) assert request_unconfirm_url in msend.call_args[1]['text'] msend.reset_mock() # this should send a confirmation email r = client.get(request_unconfirm_url) assert r.status_code == 200 assert msend.called unconfirm_url_with_digest = url_for('unconfirm_form', form_id=f1.id, digest=f1.unconfirm_digest(), _external=True) assert unconfirm_url_with_digest in msend.call_args[1]['text'] msend.reset_mock() # unconfirm this r = client.get(unconfirm_url_with_digest) assert f1.confirmed == False # should show a page with the other options assert r.status_code == 200 assert 'Select all' in r.data.decode('utf-8') assert f2.host in r.data.decode('utf-8') assert f3.host in r.data.decode('utf-8') unconfirm_multiple_url = url_for('unconfirm_multiple') assert unconfirm_multiple_url in r.data.decode('utf-8') # we can use unconfirm_multiple to unconfirm f2 assert f2.confirmed == True r = client.post(unconfirm_multiple_url, data={'form_ids': [f2.id]}) assert r.status_code == 200 assert 'Success' in r.data.decode('utf-8') assert f2.confirmed == False
def test_backwards_multiple(client, msend, confirmed_host): """ Same as previous, but now instead of having a single form, we have all, but each time only one of the them is confirmed. """ prepare() try: for host in hosts: f = Form(email=email, confirmed=(host == confirmed_host), host=host) DB.session.add(f) DB.session.commit() for referer in hosts: r = client.post( "/" + email, headers={"Referer": "http://" + referer}, data={"name": "example"}, ) assert r.status_code == 302 assert "next" in r.location assert (len(hosts) == Form.query.filter_by( host=confirmed_host).first().submissions.count()) finally: revert()
def test_backwards_single(client, msend, host): """ Here we have a single form with one of the 8 host formats, then try to submit using all the 8. Everything must succeed. """ prepare() try: f = Form(email=email, confirmed=True, host=host) DB.session.add(f) DB.session.commit() for referrer in hosts: r = client.post( "/" + email, headers={"Referer": "http://" + referrer}, data={"name": "example"}, ) assert 1 == Form.query.count() assert r.status_code == 302 assert "next" in r.location assert len(hosts) == Form.query.first().submissions.count() finally: revert()
def test_backwards_none_confirmed(client, msend): """ This time no form is confirmed. """ prepare() try: for host in hosts: f = Form(email=email, confirmed=False, host=host) DB.session.add(f) DB.session.commit() for referer in hosts: r = client.post( "/" + email, headers={"Referer": "http://" + referer}, data={"name": "example"}, ) assert r.status_code == 200 assert b"confirm" in r.get_data() assert Form.get_with(email=email, host=referer).host == hosts[0] assert Form.query.count() == len(hosts) assert Form.query.filter_by(confirmed=True).count() == 0 assert Submission.query.count() == 0 finally: revert()
def test_backwards_multiple_confirmed(client, msend, unconfirmed_host): """ Same as previous, but now instead of having a single form confirmed, we have all but one confirmed. Submissions should go through the form which they specify directly, and fallback to the first in the priority when that is not confirmed. """ prepare() try: for host in hosts: f = Form(email=email, confirmed=(host != unconfirmed_host), host=host) DB.session.add(f) DB.session.commit() for referer in hosts: r = client.post( "/" + email, headers={"Referer": "http://" + referer}, data={"name": "example"}, ) assert r.status_code == 302 assert "next" in r.location first = None for host in hosts: form = Form.query.filter_by(host=host).first() if host == unconfirmed_host: assert form.submissions.count() == 0 else: if not first: first = form continue assert form.submissions.count() == 1 assert first.submissions.count() == 2 finally: revert()
def get_or_create_form(email, host): """ Gets the form if it already exits, otherwise checks to ensure that this is a valid new form submission. If so, creates a new form. """ form = Form.get_with(email=email, host=host) if not form: if request_wants_json(): # Can't create a new ajax form unless from the dashboard ajax_error_str = ( "To prevent spam, only " + settings.UPGRADED_PLAN_NAME + " accounts may create AJAX forms." ) raise SubmitFormError((jsonify({"error": ajax_error_str}), 400)) if ( url_domain(settings.SERVICE_URL) in host and host.rstrip("/") != settings.TEST_URL ): # Bad user is trying to submit a form spoofing formspree.io g.log.info( "User attempting to create new form spoofing SERVICE_URL. Ignoring." ) raise SubmitFormError( ( render_template( "error.html", title="Unable to submit form", text="Sorry." ), 400, ) ) # all good, create form form = Form(email, host=host, confirmed=False, normalize=True) if form.disabled: raise SubmitFormError(errors.disabled_error()) return form
def create_user_and_form(client, login=True): # create user and form username = "".join( [random.choice(string.ascii_lowercase) for i in range(10)]) email = username + "@example.com" user, _ = User.register(email, PASSWORD) user.plan = Plan.gold user.emails[0].verified = True form = Form(username + "@example.com", name="example", owner=user, confirmed=True) DB.session.add(user) DB.session.add(form) DB.session.commit() if login: client.post("/login", data={"email": email, "password": PASSWORD}) return user, form
def get_or_create_form(email, host): ''' Gets the form if it already exits, otherwise checks to ensure that this is a valid new form submission. If so, creates a new form. ''' form = Form.query.filter_by(hash=HASH(email, host)).first() if not form: if request_wants_json(): # Can't create a new ajax form unless from the dashboard ajax_error_str = "To prevent spam, only " + \ settings.UPGRADED_PLAN_NAME + \ " accounts may create AJAX forms." raise SubmitFormError(jsonerror(400, {'error': ajax_error_str})) if url_domain(settings.SERVICE_URL) in host: # Bad user is trying to submit a form spoofing formspree.io g.log.info( 'User attempting to create new form spoofing SERVICE_URL. Ignoring.' ) raise SubmitFormError( (render_template('error.html', title='Unable to submit form', text='Sorry'), 400)) # all good, create form form = Form(email, host) # Check if it has been assigned using AJAX or not assign_ajax(form, request_wants_json()) if form.disabled: raise SubmitFormError(errors.disabled_error()) return form
def create_and_activate_form(client, email, host): # create user and form form = Form(email, host=host, confirmed=True) DB.session.add(form) DB.session.commit() return form
def test_recaptcha_is_rendered(client, msend): def revert(testing, seq): settings.TESTING = testing settings.FORM_AJAX_DISABLE_ACTIVATION_SEQUENCE = seq revert = partial( revert, testing=settings.TESTING, seq=settings.FORM_AJAX_DISABLE_ACTIVATION_SEQUENCE, ) settings.TESTING = False try: # create the form f = Form("*****@*****.**", confirmed=True, host="example.com") DB.session.add(f) DB.session.commit() # normal submission r = client.post( "/[email protected]", headers={"Referer": "example.com"}, data={"hello": "world"}, ) assert r.status_code == 401 # recaptcha assert b"google.com/recaptcha" in r.data assert not msend.called # ajax submission r = client.post( "/[email protected]", headers={ "Referer": "example.com", "Content-Type": "application/json" }, data=json.dumps({"hello": "world"}), ) assert r.status_code == 403 # should get a json error assert "error" in json.loads(r.data.decode("utf-8")) assert not msend.called # a form that is before ajax disable sequence shouldn't show recaptcha # when the submission is ajax settings.FORM_AJAX_DISABLE_ACTIVATION_SEQUENCE = 1 # normal submission r = client.post( "/[email protected]", headers={"Referer": "example.com"}, data={"hello": "world"}, ) assert r.status_code == 401 # recaptcha assert b"google.com/recaptcha" in r.data assert not msend.called # ajax submission r = client.post( "/[email protected]", headers={ "Referer": "example.com", "Content-Type": "application/json" }, data=json.dumps({"hello": "world"}), ) assert r.status_code == 200 assert b"google.com/recaptcha" not in r.data assert msend.called finally: revert()
def test_unconfirm_process(client, msend): # confirm some forms for the same email address f1 = Form("*****@*****.**", host="testwebsite.com", confirmed=True) DB.session.add(f1) f2 = Form("*****@*****.**", host="othertestwebsite.com", confirmed=True) DB.session.add(f2) f3 = Form("*****@*****.**", host="anothertestwebsite.com", confirmed=True) DB.session.add(f3) DB.session.commit() # try a submission r = client.post( "/[email protected]", headers={"Referer": "http://testwebsite.com"}, data={"name": "carol"}, ) assert msend.called request_unconfirm_url = url_for("request_unconfirm_form", form_id=f1.id, _external=True, _scheme="https") assert request_unconfirm_url in msend.call_args[1]["text"] msend.reset_mock() # this should send a confirmation email r = client.get(request_unconfirm_url) # actually, it should fail unless the request comes from a browser assert not msend.called # now it must work r = client.get( request_unconfirm_url, headers={ "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0" }, ) assert r.status_code == 200 assert msend.called unconfirm_url_with_digest = url_for( "unconfirm_form", form_id=f1.id, digest=f1.unconfirm_digest(), _external=True, _scheme="https", ) assert unconfirm_url_with_digest in msend.call_args[1]["text"] msend.reset_mock() # unconfirm this r = client.get(unconfirm_url_with_digest) assert f1.confirmed == False # should show a page with the other options assert r.status_code == 200 assert "Select all" in r.data.decode("utf-8") assert f2.host in r.data.decode("utf-8") assert f3.host in r.data.decode("utf-8") unconfirm_multiple_url = url_for("unconfirm_multiple") assert unconfirm_multiple_url in r.data.decode("utf-8") # we can use unconfirm_multiple to unconfirm f2 assert f2.confirmed == True r = client.post(unconfirm_multiple_url, data={"form_ids": [f2.id]}) assert r.status_code == 200 assert "Success" in r.data.decode("utf-8") assert f2.confirmed == False