def post(self, request, project):
        if not features.has(APP_STORE_CONNECT_FEATURE_NAME,
                            project.organization,
                            actor=request.user):
            return Response(status=404)

        serializer = AppStoreConnectRequestSmsSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        session = requests.Session()

        encrypted_context = serializer.validated_data.get("sessionContext")
        key = project.get_option(CREDENTIALS_KEY_NAME)

        if key is None:
            return Response(
                "Invalid state. Must first call appstoreconnect/start/ endpoint.",
                status=400)

        try:
            # recover the headers set in the first step authentication
            session_context = encrypt.decrypt_object(encrypted_context, key)
            headers = ITunesHeaders(
                session_id=session_context.get("session_id"),
                scnt=session_context.get("scnt"))
            auth_key = session_context.get("auth_key")

        except ValueError:
            return Response("Invalid validation context passed.", status=400)

        phone_info = itunes_connect.get_trusted_phone_info(
            session, service_key=auth_key, headers=headers)

        if phone_info is None:
            return Response("Could not get phone info", status=400)

        init_phone_login = itunes_connect.initiate_phone_login(
            session,
            service_key=auth_key,
            headers=headers,
            phone_id=phone_info.id,
            push_mode=phone_info.push_mode,
        )

        if init_phone_login is None:
            return Response("Phone 2fa failed", status=500)

        # success, return the new session context (add phone_id and push mode to the session context)
        session_context["phone_id"] = phone_info.id
        session_context["push_mode"] = phone_info.push_mode
        encrypted_context = encrypt.encrypt_object(session_context, key)
        return Response({"sessionContext": encrypted_context}, status=200)
    def post(self, request, project):
        if not features.has(APP_STORE_CONNECT_FEATURE_NAME,
                            project.organization,
                            actor=request.user):
            return Response(status=404)

        serializer = AppStoreCreateCredentialsSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        key = project.get_option(CREDENTIALS_KEY_NAME)

        if key is None:
            # probably stage 1 login was not called
            return Response(
                "Invalid state. Must first call appstoreconnect/start/ endpoint.",
                status=400)

        credentials = serializer.validated_data

        encrypted_context = credentials.pop("sessionContext")

        try:
            validation_context = encrypt.decrypt_object(encrypted_context, key)
            itunes_session = validation_context.get("itunes_session")
            encrypted = {
                "itunesSession": itunes_session,
                "itunesPassword": credentials.get("itunesPassword"),
                "appconnectPrivateKey":
                credentials.get("appconnectPrivateKey"),
            }
            credentials["encrypted"] = encrypt.encrypt_object(encrypted, key)
            credentials["type"] = "appStoreConnect"
            credentials["itunesCreated"] = validation_context.get(
                "itunes_created")
            credentials["id"] = uuid4().hex
            credentials["name"] = "Apple App Store Connect"
            # TODO(flub): validate this using the JSON schema in sentry.lang.native.symbolicator
        except ValueError:
            return Response("Invalid validation context passed.", status=400)
        return Response(credentials, status=200)
    def post(self, request, project):
        if not features.has(app_store_connect_feature_name(),
                            project.organization,
                            actor=request.user):
            return Response(status=404)

        serializer = AppStoreCreateCredentialsSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        key = project.get_option(credentials_key_name())

        if key is None:
            # probably stage 1 login was not called
            return Response(
                "Invalid state. Must first call appstoreconnect/start/ endpoint.",
                status=400)

        credentials = serializer.validated_data

        encrypted_context = credentials.pop("sessionContext")

        try:
            validation_context = encrypt.decrypt_object(encrypted_context, key)
            itunes_session = validation_context.get("itunes_session")
            encrypted = {
                "itunesSession": itunes_session,
                "itunesPassword": credentials.pop("itunesPassword"),
                "appconnectPrivateKey":
                credentials.pop("appconnectPrivateKey"),
            }
            credentials["encrypted"] = encrypt.encrypt_object(encrypted, key)
            credentials["type"] = "appStoreConnect"
            credentials["id"] = uuid4().hex
            credentials["name"] = "Apple App Store Connect"

        except ValueError:
            return Response("Invalid validation context passed.", status=400)
        return Response(credentials, status=200)
    def post(self, request, project):
        if not features.has(APP_STORE_CONNECT_FEATURE_NAME,
                            project.organization,
                            actor=request.user):
            return Response(status=404)

        serializer = AppStoreConnect2FactorAuthSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        encrypted_context = serializer.validated_data.get("sessionContext")
        key = project.get_option(CREDENTIALS_KEY_NAME)
        use_sms = serializer.validated_data.get("useSms")
        code = serializer.validated_data.get("code")

        if key is None:
            # probably stage 1 login was not called
            return Response(
                "Invalid state. Must first call appstoreconnect/start/ endpoint.",
                status=400)

        try:
            # recover the headers set in the first step authentication
            session_context = encrypt.decrypt_object(encrypted_context, key)
            headers = ITunesHeaders(
                session_id=session_context.get("session_id"),
                scnt=session_context.get("scnt"))
            auth_key = session_context.get("auth_key")

            session = requests.Session()

            if use_sms:
                phone_id = session_context.get("phone_id")
                push_mode = session_context.get("push_mode")
                success = itunes_connect.send_phone_authentication_confirmation_code(
                    session,
                    service_key=auth_key,
                    headers=headers,
                    phone_id=phone_id,
                    push_mode=push_mode,
                    security_code=code,
                )
            else:
                success = itunes_connect.send_authentication_confirmation_code(
                    session,
                    service_key=auth_key,
                    headers=headers,
                    security_code=code)

            if success:
                session_info = itunes_connect.get_session_info(session)

                if session_info is None:
                    return Response("session info failed", status=500)

                existing_providers = get_path(session_info,
                                              "availableProviders")
                providers = [{
                    "name": provider.get("name"),
                    "organizationId": provider.get("providerId")
                } for provider in existing_providers]
                prs_id = get_path(session_info, "user", "prsId")

                itunes_session = itunes_connect.get_session_cookie(session)
                session_context = {
                    "auth_key": auth_key,
                    "session_id": headers.session_id,
                    "scnt": headers.scnt,
                    "itunes_session": itunes_session,
                    "itunes_person_id": prs_id,
                    "itunes_created": datetime.datetime.utcnow(),
                }
                encrypted_context = encrypt.encrypt_object(
                    session_context, key)

                response_body = {
                    "sessionContext": encrypted_context,
                    "organizations": providers
                }

                return Response(response_body, status=200)
            else:
                return Response("2FA failed.", status=401)

        except ValueError:
            return Response("Invalid validation context passed.", status=400)
    def post(self, request, project):
        if not features.has(APP_STORE_CONNECT_FEATURE_NAME,
                            project.organization,
                            actor=request.user):
            return Response(status=404)

        serializer = AppStoreConnectStartAuthSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        user_name = serializer.validated_data.get("itunesUser")
        password = serializer.validated_data.get("itunesPassword")
        credentials_id = serializer.validated_data.get("id")

        key = project.get_option(CREDENTIALS_KEY_NAME)

        if key is None:
            # no encryption key for this project, create one
            key = encrypt.create_key()
            project.update_option(CREDENTIALS_KEY_NAME, key)
        else:
            # we have an encryption key, see if the credentials were not
            # supplied and we just want to re validate the session
            if user_name is None or password is None:
                # credentials not supplied use saved credentials

                credentials = get_app_store_config(project, credentials_id)
                if key is None or credentials is None:
                    return Response("No credentials provided.", status=400)

                try:
                    secrets = encrypt.decrypt_object(
                        credentials.get("encrypted"), key)
                except ValueError:
                    return Response("Invalid credentials state.", status=500)

                user_name = credentials.get("itunesUser")
                password = secrets.get("itunesPassword")

                if user_name is None or password is None:
                    return Response("Invalid credentials.", status=500)

        session = requests.session()

        auth_key = itunes_connect.get_auth_service_key(session)

        if auth_key is None:
            return Response("Could not contact itunes store.", status=500)

        if user_name is None:
            return Response("No user name provided.", status=400)
        if password is None:
            return Response("No password provided.", status=400)

        init_login_result = itunes_connect.initiate_login(
            session,
            service_key=auth_key,
            account_name=user_name,
            password=password)
        if init_login_result is None:
            return Response("ITunes login failed.", status=401)

        # send session context to be used in next calls
        session_context = {
            "auth_key": auth_key,
            "session_id": init_login_result.session_id,
            "scnt": init_login_result.scnt,
        }

        return Response(
            {"sessionContext": encrypt.encrypt_object(session_context, key)},
            status=200)
    def post(self, request, project, credentials_id):
        if not features.has(APP_STORE_CONNECT_FEATURE_NAME,
                            project.organization,
                            actor=request.user):
            return Response(status=404)

        serializer = AppStoreUpdateCredentialsSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        # get the existing credentials
        symbol_source_config = get_app_store_config(project, credentials_id)
        key = project.get_option(CREDENTIALS_KEY_NAME)

        if key is None or symbol_source_config is None:
            return Response(status=404)

        try:
            secrets = encrypt.decrypt_object(
                symbol_source_config.pop("encrypted"), key)
        except ValueError:
            return Response(status=500)

        # get the new credentials
        new_credentials = serializer.validated_data
        encrypted_context = new_credentials.get("sessionContext")

        new_itunes_session = None
        new_itunes_created = None
        if encrypted_context is not None:
            try:
                validation_context = encrypt.decrypt_object(
                    encrypted_context, key)
                new_itunes_session = validation_context.get("itunes_session")
                new_itunes_created = validation_context.get("itunes_created")
            except ValueError:
                return Response("Invalid validation context passed.",
                                status=400)

        new_secrets = {}

        if new_itunes_session is not None:
            new_secrets["itunesSession"] = new_itunes_session

        new_itunes_password = new_credentials.get("itunesPassword")
        if new_itunes_password is not None:
            new_secrets["itunesPassword"] = new_itunes_password

        new_appconnect_private_key = new_credentials.get(
            "appconnectPrivateKey")
        if new_appconnect_private_key is not None:
            new_secrets["appconnectPrivateKey"] = new_appconnect_private_key

        # merge the new and existing credentials

        try:
            secrets.update(new_secrets)
            symbol_source_config.update(new_credentials)

            symbol_source_config["encrypted"] = encrypt.encrypt_object(
                secrets, key)
            symbol_source_config["itunesCreated"] = new_itunes_created
            symbol_source_config["id"] = uuid4().hex
            # TODO(flub): validate this using the JSON schema in sentry.lang.native.symbolicator
        except ValueError:
            return Response("Invalid validation context passed.", status=400)
        return Response(symbol_source_config, status=200)
    def post(self, request, project, credentials_id):
        if not features.has(app_store_connect_feature_name(),
                            project.organization,
                            actor=request.user):
            return Response(status=404)

        serializer = AppStoreUpdateCredentialsSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        # get the existing credentials
        credentials = get_app_store_credentials(project, credentials_id)
        key = project.get_option(credentials_key_name())

        if key is None or credentials is None:
            return Response(status=404)

        try:
            secrets = encrypt.decrypt_object(credentials.pop("encrypted"), key)
        except ValueError:
            return Response(status=500)

        # get the new credentials
        new_credentials = serializer.validated_data
        encrypted_context = new_credentials.get("sessionContext")

        new_itunes_session = None
        if encrypted_context is not None:
            try:
                validation_context = encrypt.decrypt_object(
                    encrypted_context, key)
                new_itunes_session = validation_context.get("itunes_session")
            except ValueError:
                return Response("Invalid validation context passed.",
                                status=400)

        new_secrets = {}

        if new_itunes_session is not None:
            new_secrets["itunesSession"] = new_itunes_session

        new_itunes_password = new_credentials.get("itunesPassword")
        if new_itunes_password is not None:
            new_secrets["itunesPassword"] = new_itunes_password

        new_appconnect_private_key = new_credentials.get(
            "appconnectPrivateKey")
        if new_appconnect_private_key is not None:
            new_secrets["appconnectPrivateKey"] = new_appconnect_private_key

        # merge the new and existing credentials

        try:
            secrets.update(new_secrets)
            credentials.update(new_credentials)

            credentials["encrypted"] = encrypt.encrypt_object(secrets, key)
            credentials["id"] = uuid4().hex

        except ValueError:
            return Response("Invalid validation context passed.", status=400)
        return Response(credentials, status=200)