def test_signup_invalid_email(db): with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="frodo", email="a"))) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.INVALID_EMAIL with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="frodo", email="a@b"))) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.INVALID_EMAIL with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="frodo", email="a@b."))) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.INVALID_EMAIL with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="frodo", email="[email protected]"))) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.INVALID_EMAIL
def test_signup_continue_with_email(db): testing_email = f"{random_hex(12)}@couchers.org.invalid" with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="frodo", email=testing_email))) flow_token = res.flow_token assert flow_token # continue with same email, should just send another email to the user with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: res = auth_api.SignupFlow( auth_pb2.SignupFlowReq(basic=auth_pb2.SignupBasic( name="frodo", email=testing_email))) assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION assert e.value.details() == errors.SIGNUP_FLOW_EMAIL_STARTED_SIGNUP
def test_signup_existing_email(db): # Signed up user user, _ = generate_user() with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq(basic=auth_pb2.SignupBasic( name="frodo", email=user.email))) assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION assert e.value.details() == errors.SIGNUP_FLOW_EMAIL_TAKEN
def test_signup_token_regression(db): # Repro steps: # 1. Start a signup # 2. Confirm the email # 3. Start a new signup with the same email # Expected: send a link to the email to continue signing up. # Actual: `AttributeError: 'SignupFlow' object has no attribute 'token'` testing_email = f"{random_hex(12)}@couchers.org.invalid" # 1. Start a signup with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="frodo", email=testing_email))) flow_token = res.flow_token assert flow_token # 2. Confirm the email with session_scope() as session: email_token = (session.execute( select(SignupFlow).where( SignupFlow.flow_token == flow_token)).scalar_one().email_token) with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, email_token=email_token, )) # 3. Start a new signup with the same email with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: res = auth_api.SignupFlow( auth_pb2.SignupFlowReq(basic=auth_pb2.SignupBasic( name="frodo", email=testing_email))) assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION assert e.value.details() == errors.SIGNUP_FLOW_EMAIL_STARTED_SIGNUP
def test_enforce_community_memberships_for_user(testing_communities): """ Make sure the user is added to the right communities on signup """ with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="testing", email="*****@*****.**"), account=auth_pb2.SignupAccount( username="******", password="******", birthdate="1970-01-01", gender="Bot", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, city="Country 1, Region 1, City 2", # lat=8, lng=1 is equivalent to creating this coordinate with create_coordinate(8) lat=8, lng=1, radius=500, accept_tos=True, ), feedback=auth_pb2.ContributorForm(), accept_community_guidelines=wrappers_pb2.BoolValue(value=True), )) with session_scope() as session: email_token = (session.execute( select(SignupFlow).where(SignupFlow.flow_token == res.flow_token)).scalar_one().email_token) with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq(email_token=email_token)) user_id = res.auth_res.user_id # now check the user is in the right communities with session_scope() as session: w_id = get_community_id(session, "Global") c1_id = get_community_id(session, "Country 1") c1r1_id = get_community_id(session, "Country 1, Region 1") c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2") token = get_session_cookie_token(metadata_interceptor) with communities_session(token) as api: res = api.ListUserCommunities(communities_pb2.ListUserCommunitiesReq()) assert [c.community_id for c in res.communities] == [w_id, c1_id, c1r1_id, c1r1c2_id]
def test_signup_without_password(db): with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="Räksmörgås", email="*****@*****.**"), account=auth_pb2.SignupAccount( username="******", password="******", city="Minas Tirith", birthdate="9999-12-31", # arbitrary future birthdate gender="Robot", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, lat=1, lng=1, radius=100, accept_tos=True, ), feedback=auth_pb2.ContributorForm(), )) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.PASSWORD_TOO_SHORT
def test_complete_signup(db): testing_email = f"{random_hex(12)}@couchers.org.invalid" with auth_api_session() as (auth_api, metadata_interceptor): reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq(basic=auth_pb2.SignupBasic( name="Tester", email=testing_email))) flow_token = reply.flow_token with auth_api_session() as (auth_api, metadata_interceptor): # Invalid username with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, account=auth_pb2.SignupAccount( username="******", password="******", city="Minas Tirith", birthdate="1980-12-31", gender="Robot", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, lat=1, lng=1, radius=100, accept_tos=True, ), )) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.INVALID_USERNAME with auth_api_session() as (auth_api, metadata_interceptor): # Invalid name with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq(basic=auth_pb2.SignupBasic( name=" ", email=f"{random_hex(12)}@couchers.org.invalid"))) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.INVALID_NAME with auth_api_session() as (auth_api, metadata_interceptor): # Hosting status required with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, account=auth_pb2.SignupAccount( username="******", password="******", city="Minas Tirith", birthdate="1980-12-31", gender="Robot", hosting_status=None, lat=1, lng=1, radius=100, accept_tos=True, ), )) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.HOSTING_STATUS_REQUIRED user, _ = generate_user() with auth_api_session() as (auth_api, metadata_interceptor): # Username unavailable with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, account=auth_pb2.SignupAccount( username=user.username, password="******", city="Minas Tirith", birthdate="1980-12-31", gender="Robot", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, lat=1, lng=1, radius=100, accept_tos=True, ), )) assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION assert e.value.details() == errors.USERNAME_NOT_AVAILABLE with auth_api_session() as (auth_api, metadata_interceptor): # Invalid coordinate with pytest.raises(grpc.RpcError) as e: reply = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, account=auth_pb2.SignupAccount( username="******", password="******", city="Minas Tirith", birthdate="1980-12-31", gender="Robot", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, lat=0, lng=0, radius=100, accept_tos=True, ), )) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT assert e.value.details() == errors.INVALID_COORDINATE
def test_signup_invalid_birthdate(db): with auth_api_session() as (auth_api, metadata_interceptor): with pytest.raises(grpc.RpcError) as e: auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="Räksmörgås", email="*****@*****.**"), account=auth_pb2.SignupAccount( username="******", password="******", city="Minas Tirith", birthdate="9999-12-31", # arbitrary future birthdate gender="Robot", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, lat=1, lng=1, radius=100, accept_tos=True, ), feedback=auth_pb2.ContributorForm(), )) assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION assert e.value.details() == errors.INVALID_BIRTHDATE res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="Christopher", email="*****@*****.**"), account=auth_pb2.SignupAccount( username="******", password="******", city="New York City", birthdate= "2000-12-31", # arbitrary birthdate older than 18 years gender="Helicopter", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, lat=1, lng=1, radius=100, accept_tos=True, ), feedback=auth_pb2.ContributorForm(), )) assert res.flow_token with pytest.raises(grpc.RpcError) as e: auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="Franklin", email="*****@*****.**"), account=auth_pb2.SignupAccount( username="******", password="******", city="Los Santos", birthdate="2010-04-09", # arbitrary birthdate < 18 yrs gender="Male", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, lat=1, lng=1, radius=100, accept_tos=True, ), feedback=auth_pb2.ContributorForm(), )) assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION assert e.value.details() == errors.INVALID_BIRTHDATE with session_scope() as session: assert session.execute( select(func.count()).select_from(SignupFlow)).scalar_one() == 1
def test_signup_incremental(db): with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq(basic=auth_pb2.SignupBasic( name="testing", email="*****@*****.**"), )) flow_token = res.flow_token assert res.flow_token assert not res.HasField("auth_res") assert not res.need_basic assert res.need_account assert res.need_feedback assert res.need_verify_email assert res.need_accept_community_guidelines # read out the signup token directly from the database for now with session_scope() as session: flow = session.execute( select(SignupFlow).where( SignupFlow.flow_token == flow_token)).scalar_one() assert flow.email_sent assert not flow.email_verified email_token = flow.email_token with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq(flow_token=flow_token)) assert res.flow_token == flow_token assert not res.HasField("auth_res") assert not res.need_basic assert res.need_account assert res.need_feedback assert res.need_verify_email assert res.need_accept_community_guidelines # Add feedback with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, feedback=auth_pb2.ContributorForm( ideas="I'm a robot, incapable of original ideation", features="I love all your features", experience="I haven't done couch surfing before", contribute=auth_pb2.CONTRIBUTE_OPTION_YES, contribute_ways=["serving", "backend"], expertise= "I'd love to be your server: I can compute very fast, but only simple opcodes", ), )) assert res.flow_token == flow_token assert not res.HasField("auth_res") assert not res.need_basic assert res.need_account assert not res.need_feedback assert res.need_verify_email assert res.need_accept_community_guidelines # Agree to community guidelines with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, accept_community_guidelines=wrappers_pb2.BoolValue(value=True), )) assert res.flow_token == flow_token assert not res.HasField("auth_res") assert not res.need_basic assert res.need_account assert not res.need_feedback assert res.need_verify_email assert not res.need_accept_community_guidelines # Verify email with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, email_token=email_token, )) assert res.flow_token == flow_token assert not res.HasField("auth_res") assert not res.need_basic assert res.need_account assert not res.need_feedback assert not res.need_verify_email assert not res.need_accept_community_guidelines # Finally finish off account info with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( flow_token=flow_token, account=auth_pb2.SignupAccount( username="******", password="******", birthdate="1970-01-01", gender="Bot", hosting_status=api_pb2.HOSTING_STATUS_MAYBE, city="New York City", lat=40.7331, lng=-73.9778, radius=500, accept_tos=True, ), )) assert not res.flow_token assert res.HasField("auth_res") assert res.auth_res.user_id assert not res.auth_res.jailed assert not res.need_basic assert not res.need_account assert not res.need_feedback assert not res.need_verify_email assert not res.need_accept_community_guidelines user_id = res.auth_res.user_id sess_token = get_session_cookie_token(metadata_interceptor) with api_session(sess_token) as api: res = api.GetUser(api_pb2.GetUserReq(user=str(user_id))) assert res.username == "frodo" assert res.gender == "Bot" assert res.hosting_status == api_pb2.HOSTING_STATUS_MAYBE assert res.city == "New York City" assert res.lat == 40.7331 assert res.lng == -73.9778 assert res.radius == 500 with session_scope() as session: form = session.execute(select(ContributorForm)).scalar_one() assert form.ideas == "I'm a robot, incapable of original ideation" assert form.features == "I love all your features" assert form.experience == "I haven't done couch surfing before" assert form.contribute == ContributeOption.yes assert form.contribute_ways == ["serving", "backend"] assert form.expertise == "I'd love to be your server: I can compute very fast, but only simple opcodes"
def _quick_signup(): with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq( basic=auth_pb2.SignupBasic(name="testing", email="*****@*****.**"), account=auth_pb2.SignupAccount( username="******", password="******", birthdate="1970-01-01", gender="Bot", hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST, city="New York City", lat=40.7331, lng=-73.9778, radius=500, accept_tos=True, ), feedback=auth_pb2.ContributorForm(), accept_community_guidelines=wrappers_pb2.BoolValue(value=True), )) flow_token = res.flow_token assert res.flow_token assert not res.HasField("auth_res") assert not res.need_basic assert not res.need_account assert not res.need_feedback assert res.need_verify_email # read out the signup token directly from the database for now with session_scope() as session: flow = session.execute( select(SignupFlow).where( SignupFlow.flow_token == flow_token)).scalar_one() assert flow.email_sent assert not flow.email_verified email_token = flow.email_token with auth_api_session() as (auth_api, metadata_interceptor): res = auth_api.SignupFlow( auth_pb2.SignupFlowReq(email_token=email_token)) assert not res.flow_token assert res.HasField("auth_res") assert res.auth_res.user_id assert not res.auth_res.jailed assert not res.need_basic assert not res.need_account assert not res.need_feedback assert not res.need_verify_email user_id = res.auth_res.user_id # make sure we got the right token in a cookie with session_scope() as session: token = (session.execute( select(UserSession).join( User, UserSession.user_id == User.id).where( User.username == "frodo")).scalar_one()).token assert get_session_cookie_token(metadata_interceptor) == token