def test_tracing_interceptor_abort(db): def TestRpc(request, context): context.abort(grpc.StatusCode.FAILED_PRECONDITION, "now a grpc abort") with interceptor_dummy_api( TestRpc, interceptors=[TracingInterceptor()], request_type=auth_pb2.SignupAccount, response_type=auth_pb2.AuthReq, ) as call_rpc: with pytest.raises(Exception): call_rpc(auth_pb2.SignupAccount(password="******", username="******")) with session_scope() as session: trace = session.execute(select(APICall)).scalar_one() assert trace.method == "/testing.Test/TestRpc" assert trace.status_code == "FAILED_PRECONDITION" assert not trace.user_id assert "now a grpc abort" in trace.traceback req = auth_pb2.SignupAccount.FromString(trace.request) assert not req.password assert req.username == "not removed" assert not trace.response _check_histogram_labels("/testing.Test/TestRpc", "Exception", "FAILED_PRECONDITION", 1)
def test_tracing_interceptor_sensitive(db): def TestRpc(request, context): return auth_pb2.AuthReq(user="******", password="******") with interceptor_dummy_api( TestRpc, interceptors=[TracingInterceptor()], request_type=auth_pb2.SignupAccount, response_type=auth_pb2.AuthReq, ) as call_rpc: call_rpc(auth_pb2.SignupAccount(password="******", username="******")) with session_scope() as session: trace = session.execute(select(APICall)).scalar_one() assert trace.method == "/testing.Test/TestRpc" assert not trace.status_code assert not trace.user_id assert not trace.traceback req = auth_pb2.SignupAccount.FromString(trace.request) assert not req.password assert req.username == "not removed" res = auth_pb2.AuthReq.FromString(trace.response) assert res.user == "this is not secret" assert not res.password _check_histogram_labels("/testing.Test/TestRpc", "", "", 1)
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