Esempio n. 1
0
def validate_number(phone_number):
    """ Validate a phone number, converting it to E.164 format.
    """
    raise UnauthorizedException() # Disable for now.

    logger.debug("in core.api.users.validate_number(" +
                 "phone_number=%s)" % repr(phone_number))

    if phone_number == None:
        raise InvalidParametersException()

    return utils.format_phone_number(phone_number)
Esempio n. 2
0
def phone_number_exists(phone_number):
    """ Return True iff the given phone number exists.
    """
    raise UnauthorizedException() # Disable for now.

    logger.debug("in core.api.users.phone_number_exists(" +
                 "phone_number=%s)" % repr(phone_number))

    if phone_number == None:
        raise InvalidParametersException()
    else:
        phone_number = utils.format_phone_number(phone_number)
        return User.objects.filter(phone_number=phone_number).exists()
Esempio n. 3
0
    def test_send_verification_code(self):
        """ Test users/send_verification_code.
        """
        # Create a user with a phone number, for testing.

        formatted_number = utils.format_phone_number(PHONE_NUMBER)

        User.objects.filter(phone_number=formatted_number).delete()

        user = users.create(phone_number=PHONE_NUMBER)

        # Set up a signal listener to check that the verification message is
        # being sent via Twilio.

        self.twilio_sms_sent   = False # initially.
        self.twilio_from_phone = None  # ditto.
        self.twilio_to_phone   = None  # ditto.

        def twilio_signal_handler(sender, **kwargs):
            self.twilio_sms_sent   = True
            self.twilio_from_phone = kwargs.get("from_phone")
            self.twilio_to_phone   = kwargs.get("to_phone")

        signals.twilio_sms_sent.connect(twilio_signal_handler)

        # Ask the user API to send the verification code.  Note that we disable
        # Twilio so that no actual SMS is sent.

        with self.settings(ENABLE_TWILIO=False):
            users.send_verification_code(user_id=user['id'])

        # Check that the Twilio gateway sent the verification message.

        self.assertTrue(self.twilio_sms_sent)
        self.assertEqual(self.twilio_from_phone, settings.SYSTEM_PHONE_NUMBER)
        self.assertEqual(self.twilio_to_phone, formatted_number)

        # Run the test again, this time supplying the phone number rather than
        # the user ID.

        self.twilio_sms_sent = False

        with self.settings(ENABLE_TWILIO=False):
            users.send_verification_code(phone_number=PHONE_NUMBER)

        self.assertTrue(self.twilio_sms_sent)

        # Finally, clean everything up.

        signals.twilio_sms_sent.disconnect(twilio_signal_handler)
Esempio n. 4
0
def verify_user_owns_number(session, phone_number, verification_code):
    """ Verify that the currently logged-in user owns the given phone number.
    """
    raise UnauthorizedException() # Disable for now.

    logger.debug("in core.api.users.verify_user_owns_number(" +
                 "session=%s, phone_number=%s, verification_code=%s)" %
                 (repr(session), repr(phone_number), repr(verification_code)))

    if session == None or phone_number == None or verification_code == None:
        raise InvalidParametersException()

    sessionHandler.validate(session)
    user = sessionHandler.get_user(session)

    phone_number = utils.format_phone_number(phone_number)

    try:
        user_with_phone = User.objects.get(phone_number=phone_number)
    except User.DoesNotExist:
        user_with_phone = None

    if user_with_phone == None:
        raise NoSuchPhoneNumberException()

    if verification_code != user_with_phone.verification_code:
        raise UnauthorizedException()

    if user == user_with_phone:
        # The user already has this phone number.  Simply verify it.
        user.verified = True
        user.save()
        return

    # If we get here, the phone number was originally owned by someone else.
    # Transfer the phone number over to the currently logged-in user.

    user.phone_number      = user_with_phone.phone_number
    user.verification_code = user_with_phone.verification_code
    user.verified          = True
    user.save()

    user_with_phone.phone_number      = None
    user_with_phone.verification_code = None
    user_with_phone.verified          = False
    user_with_phone.save()
Esempio n. 5
0
def send_verification_code(user_id=None, phone_number=None):
    """ Calculate and send out a verification code to a phone number.
    """
    raise UnauthorizedException() # Disable for now.

    logger.debug("in core.api.users.send_verification_code(" +
                 "user_id=%s, phone_number=%s)" %
                 (repr(user_id), repr(phone_number)))

    # Get the user to send the verification message to.

    if user_id != None:
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            raise NoSuchUserException()
    elif phone_number != None:
        phone_number = utils.format_phone_number(phone_number)

        try:
            user = User.objects.get(phone_number=phone_number)
        except User.DoesNotExist:
            raise NoSuchPhoneNumberException()
    else:
        raise InvalidParametersException()

    # Check that the user has a phone number.

    if user.phone_number == None:
        raise NoPhoneNumberException()

    # Calculate a new verification code for this user.

    user.verification_code = utils.random_digits(min_length=4, max_length=4)
    user.save()

    # Finally, send the verification code to the user's phone as an SMS
    # message.

    message = settings.SMS_TEXT_VERIFICATION_CODE % user.verification_code

    twilio_gateway.send_sms(from_phone=settings.SYSTEM_PHONE_NUMBER,
                            to_phone=user.phone_number,
                            sms_message=message)
Esempio n. 6
0
    def test_phone_number_exists(self):
        """ Test users/phone_number_exists.
        """
        # Create a user with a phone number.

        username = utils.random_username()
        password = utils.random_password()

        formatted_number = utils.format_phone_number(PHONE_NUMBER)

        User.objects.filter(phone_number=formatted_number).delete()

        user = users.create(phone_number=PHONE_NUMBER)

        # Check that the phone number can be found.

        self.assertTrue(users.phone_number_exists(PHONE_NUMBER))

        # Check that a different phone number can't be found.

        self.assertFalse(users.phone_number_exists(PHONE_NUMBER+"123"))
Esempio n. 7
0
    def test_create(self):
        """ Test users/create.
        """
        # Test the process of creating a user without any details.

        user = users.create()
        self.assertItemsEqual(user.keys(),
                              ["id", "ad_hoc", "verified", "created_at",
                               "updated_at"])
        self.assertTrue(user['ad_hoc'])

        # Test the process of creating a user with a username and password.

        user = users.create(username=utils.random_username(),
                            password=utils.random_password())
        self.assertItemsEqual(user.keys(),
                              ["id", "ad_hoc", "username", "verified",
                               "created_at", "updated_at"])
        self.assertFalse(user['ad_hoc'])

        # Check that a default topic has been created for the new user.

        has_default_topic = False

        for topic in Topic.objects.filter(user_id=user['id']):
            if topic.default:
                has_default_topic = True
                break

        self.assertTrue(has_default_topic)

        # Check that we can't create a user with an invalid username.

        with self.assertRaises(InvalidUsernameException):
            user = users.create(username="******", password="******")

        # Check that we can't create a user with an invalid password.

        with self.assertRaises(InvalidPasswordException):
            user = users.create(username=utils.random_username(),
                                password="******")

        # Check that we can't create a user with a username but no password.

        with self.assertRaises(InvalidParametersException):
            user = users.create(username=utils.random_username(),
                                password=None)

        # Check that we can't create a user with a password but not username.

        with self.assertRaises(InvalidParametersException):
            user = users.create(username=None,
                                password=utils.random_password())

        # Check that we can create a user with a valid phone number, and that
        # the phone number is converted to E.164 standard.

        formatted_number = utils.format_phone_number(PHONE_NUMBER)

        User.objects.filter(phone_number=formatted_number).delete()

        user = users.create(phone_number=PHONE_NUMBER)

        self.assertEqual(user['phone_number'], formatted_number)

        # Check that we can't create a second user with the same number.

        with self.assertRaises(DuplicatePhoneNumberException):
            user = users.create(phone_number=PHONE_NUMBER)

        # Check that we can't create a user with an invalid phone number.

        with self.assertRaises(InvalidPhoneNumberException):
            user = users.create(phone_number="INVALID")

        # Check that we can't create two users with the same username.

        username = utils.random_username()
        password = utils.random_password()

        user1 = users.create(username=username, password=password)
        with self.assertRaises(DuplicateUsernameException):
            user2 = users.create(username=username, password=password)
Esempio n. 8
0
    def test_login(self):
        """ Test users/login.
        """
        # Try logging in without any parameters.  This should create a new ad
        # hoc user on-the-fly.

        session_token = users.login()
        self.assertTrue(users.get(session_token)['ad_hoc'])

        # Create an ad-hoc user, and log in using the user ID.

        user_id = users.create()['id']
        session_token = users.login(user_id=user_id)

        # Create a user with a username, password and phone number, for testing.

        username = utils.random_username()
        password = utils.random_password()

        formatted_number = utils.format_phone_number(PHONE_NUMBER)

        User.objects.filter(phone_number=formatted_number).delete()

        user_id = users.create(username=username,
                               password=password,
                               phone_number=PHONE_NUMBER)['id']

        # Create two random verification codes, making sure they're different.

        while True:
            code_1 = utils.random_letters(min_length=4, max_length=4)
            code_2 = utils.random_letters(min_length=4, max_length=4)

            if code_1 != code_2:
                break
            else:
                continue

        # Store the first verification code into the User object.

        user = User.objects.get(id=user_id)
        user.verification_code = code_1
        user.verified          = False
        user.save()

        # Attempt to log in using the supplied phone number and verification
        # code, deliberately using the wrong code.  This should fail.

        with self.assertRaises(LoginRejectedException):
            session_token = users.login(phone_number=PHONE_NUMBER,
                                        verification_code=code_2)

        # Attempt to log in using the username and an incorrect password.  Once
        # again, this should fail.

        with self.assertRaises(LoginRejectedException):
            session_token = users.login(username=username,
                                        password=password+"X")

        # Now try logging in with the correct username and password.  This
        # should succeed.

        session_token = users.login(username=username,
                                    password=password)

        sessionHandler.validate(session_token)

        # Finally, try logging in again using the phone number and verification
        # code.  This should not only log the user it, but also verify the
        # phone number.

        session_token = users.login(phone_number=PHONE_NUMBER,
                                    verification_code=code_1)

        sessionHandler.validate(session_token)

        user = User.objects.get(id=user_id)

        self.assertEqual(user.verified, True)
Esempio n. 9
0
def update(session, username=None, password=None, phone_number=None):
    """ Update the details of the currently logged-in user.
    """
    raise UnauthorizedException() # Disable for now.

    logger.debug("in core.api.users.update(" +
                 "session=%s, username=%s, password=%s, phone_number=%s)" %
                 (repr(session), repr(username), repr(password),
                  repr(phone_number)))

    if session == None:
        raise InvalidParametersException()

    sessionHandler.validate(session)
    user = sessionHandler.get_user(session)

    # Remember if the user had a username or password.

    if user.username not in ["", None]:
        had_username = True
    else:
        had_username = False

    if user.password_salt not in ["", None]:
        had_password = True
    else:
        had_password = False

    # If we're setting a username and password for this user, and we didn't
    # have one previously, create a 3taps Identity for this user.  Note that
    # this may fail, if the username is already in use.

    if not had_username and username != None:
        if password == None: raise InvalidParametersException()
        _check_username(username)
        _check_password(password)

        # Try creating this user within the 3taps Identity API.

        success,response = identity_api.create(username, password)
        if not success:
            if response.startswith("403 error"):
                raise DuplicateUsernameException()
            else:
                raise InvalidParametersException()

        # Check that we don't have a local user with that username.

        try:
            existing_user = User.objects.get(username__iexact=username)
        except User.DoesNotExist:
            existing_user = None

        if existing_user != None:
            raise DuplicateUsernameException()

        # Finally, save the updated user details into our database.

        salt = response['server_salt']
        hash = hashlib.md5(password + salt).hexdigest()

        user.uses_identity_api = True
        user.username          = username
        user.identity_api_salt = salt
        user.identity_api_hash = hash
        user.save()

    # If we're changing the username for this user, ask the 3taps Identity API
    # to change the username.  Note that this may fail, if the new username is
    # already in use.

    if had_username and username != None and username != user.username:
        success,response = identity_api.login(user.username,
                                              pass_hash=user.identity_api_hash)
        if not success:
            raise UnauthorizedException()

        session = response

        success,response = identity_api.update(session,
                                               {'username' : username})
        if not success:
            if response.startswith("403 error"):
                raise DuplicateUsernameException()
            else:
                raise InvalidParametersException()

        identity_api.logout(session)

        # Check that we don't have a local user with that username.

        try:
            existing_user = User.objects.get(username__iexact=username)
        except User.DoesNotExist:
            existing_user = None

        if existing_user != None:
            raise DuplicateUsernameException()

        # Finally, save the updated user details into our database.

        user.username = username
        user.save()

    # If we're changing the password for this user, ask the 3taps Identity API
    # to change the password.

    if password != None:
        if user.username in ["", None]:
            # We can't change the password if we don't have a username.
            raise InvalidParametersException()

        if user.uses_identity_api:
            success,response = \
                    identity_api.login(user.username,
                                       pass_hash=user.identity_api_hash)
        else:
            success,response = \
                    identity_api.login(user.username,
                                       password="******")

        if not success:
            raise UnauthorizedException()

        session = response

        success,response = identity_api.update(session,
                                               {'username' : username})
        if not success:
            if response.startswith("403 error"):
                raise DuplicateUsernameException()
            else:
                raise InvalidParametersException()

        identity_api.logout(session)

        salt = response['server_salt']
        hash = hashlib.md5(password + salt).hexdigest()

        user.uses_identity_api = True
        user.identity_api_salt = salt
        user.identity_api_hash = hash
        user.save()

    # If we've been asked to update the user's phone number, do so.

    # NOTE: someone was using this to hack our system, so I've disabled it.

    if False: # phone_number != None:
        if phone_number == "":
            user.phone_number = None # Remove current phone number.
        else:
            phone_number = utils.format_phone_number(phone_number)

            try:
                existing_user = User.objects.get(phone_number=phone_number)
            except User.DoesNotExist:
                existing_user = None

            if existing_user != None and user.id != existing_user.id:
                raise DuplicatePhoneNumberException()

        user.phone_number = phone_number

    # If this was an ad hoc user who we're now making permanent, change their
    # "ad hoc" status, and create a new default topic for the user.

    if user.ad_hoc and (username != None or password != None or
                        phone_number != None):
        user.ad_hoc = False
        _create_default_topic(user)

    # If we have been given a username and password for this user, record them
    # as signing up.

    if not had_username and not had_password:
        if username not in ["", None] and password not in ["", None]:
            eventRecorder.record_event(eventRecorder.EVENT_TYPE_NEW_USER_SIGNUP)

    # Finally, save the updated user and return a copy of it back to the
    # caller.

    user.updated_at = datetime.datetime.utcnow()
    user.save()

    return user.to_dict()
Esempio n. 10
0
def create(username=None, password=None, phone_number=None):
    """ Create a new User within the system.
    """
    raise UnauthorizedException() # Disable for now.

    logger.debug("in core.api.users.create(" +
                 "username=%s, password=%s, phone_number=%s)" %
                 (repr(username), repr(password), repr(phone_number)))

    if username     == "": username     = None
    if password     == "": password     = None
    if phone_number == "": phone_number = None

    if username == None and password == None and phone_number == None:
        ad_hoc = True
    else:
        ad_hoc = False

    if username != None: _check_username(username)
    if password != None: _check_password(password)

    if username != None or password != None:
        if username == None or password == None:
            # username and password must both be set at the same time.
            raise InvalidParametersException()

    if phone_number != None:
        phone_number = utils.format_phone_number(phone_number)

        try:
            existing_user = User.objects.get(phone_number=phone_number)
        except User.DoesNotExist:
            existing_user = None

        if existing_user != None:
            raise DuplicatePhoneNumberException()

    if username != None:
        # The user is attempting to create a new user with a username and
        # password.  Try to create the 3taps identity for this new user, and
        # raise a DuplicateUsernameException if the user already exists.
        success,response = identity_api.create(username, password)
        if not success:
            if response.startswith("403 error"):
                raise DuplicateUsernameException()
            else:
                raise InvalidParametersException()

    user = User()

    user.ad_hoc   = ad_hoc
    user.username = username

    if username != None:
        salt = response['server_salt']
        hash = hashlib.md5(password + salt).hexdigest()

        user.uses_identity_api = True
        user.identity_api_salt = salt
        user.identity_api_hash = hash
    else:
        user.uses_identity_api = False
        user.identity_api_hash = None
        user.identity_api_salt = None

    user.phone_number      = phone_number
    user.verification_code = None
    user.verified          = False
    user.created_at        = datetime.datetime.utcnow()
    user.updated_at        = datetime.datetime.utcnow()
    user.save()

    # If the new user has a username and password, record it as a new user
    # signup.

    if username != None and password != None:
        eventRecorder.record_event(eventRecorder.EVENT_TYPE_NEW_USER_SIGNUP)

    # While we're at it, create a default topic for the new user if they're not
    # an ad hoc user.

    if not ad_hoc:
        _create_default_topic(user)

    # Finally, return the new user's details to the caller.

    return user.to_dict()
Esempio n. 11
0
def login(user_id=None,
          username=None, password=None,
          phone_number=None, verification_code=None):
    """ Log a user in, creating a new login session.
    """
    raise UnauthorizedException() # Disable for now.

    logger.debug("in core.api.users.login(" +
                 "user_id=%s, username=%s, password=%s, phone=%s, code=%s)" %
                 (repr(user_id), repr(username), repr(password),
                  repr(phone_number), repr(verification_code)))

    if user_id != None:
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            raise NoSuchUserException()
        if not user.ad_hoc:
            raise UnauthorizedException()
    elif username != None and password != None:
        # Log in using a username and password.  Note that we have to use the
        # 3taps identity API for this.

        try:
            user = User.objects.get(username__iexact=username)
        except User.DoesNotExist:
            # We don't know about this user, but that doesn't mean the user
            # doesn't exist.  It could be that the user already has an identity
            # within the 3taps Identity API, but hasn't used MessageMe before.

            # See if the user exists in the identity API.

            success,response = identity_api.login(username=username,
                                                  password=password)
            if success:
                identity_api.logout(response)

                # Create a MessageMe record for this user.

                salt = response['server_salt']
                hash = hashlib.md5(password + salt).hexdigest()

                user = User()
                user.username          = username
                user.uses_identity_api = True
                user.identity_api_salt = salt
                user.identity_api_hash = hash
                user.phone_number      = phone_number
                user.verification_code = None
                user.verified          = False
                user.created_at        = datetime.datetime.utcnow()
                user.updated_at        = datetime.datetime.utcnow()
                user.save()

                eventRecorder.record_event(
                    eventRecorder.EVENT_TYPE_NEW_USER_SIGNUP)
                _create_default_topic(user)
            else:
                # We don't know about this user, and the 3taps Identity API
                # doesn't either -> give up.
                raise LoginRejectedException()

        if user.uses_identity_api:
            # Ask the 3taps Identity API to validate the supplied username and
            # password.
            salt = user.identity_api_salt
            hash = hashlib.md5(password + salt).hexdigest()

            success,response = identity_api.login(username=username,
                                                  pass_hash=hash)
            if success:
                identity_api.logout(response)

                # Update the password hash, just in case the user changed their
                # password.

                salt = response['server_salt']
                hash = hashlib.md5(password + salt).hexdigest()

                user.identity_api_salt = salt
                user.identity_api_hash = hash
                user.save()
            else:
                raise LoginRejectedException()
        else:
            # We haven't yet migrated this user over to the identity API.  We
            # first check the password against the old password hash to see if
            # it matches our private user details.

            hash = bcrypt.hashpw(password, user.password_salt)
            if hash == user.password_hash:
                # We know the user entered the correct password.  Try logging
                # in with the "mm_temp" password, and if this works update the
                # user's details to use the supplied (real) password.
                success,response = identity_api.login(username=user.username,
                                                      password="******")
                if success:
                    session = response
                    ignore = identity_api.update(session,
                                                 {'password' : password})
                    identity_api.logout(session)

                    salt = response['server_salt']
                    hash = hashlib.md5(password + salt).hexdigest()

                    user.uses_identity_api = True
                    user.identity_api_salt = salt
                    user.identity_api_hash = hash
                    user.save()
                else:
                    # The user may have updated their password using another
                    # client of the 3taps Identity API.  Try logging in using
                    # the supplied password.
                    success,response = \
                            identity_api.login(username=user.username,
                                               password=password)
                    if success:
                        session = response
                        identity_api.logout(session)

                        salt = response['server_salt']
                        hash = hashlib.md5(password + salt).hexdigest()

                        user.uses_identity_api = True
                        user.identity_api_salt = salt
                        user.identity_api_hash = hash
                        user.save()
                    else:
                        # We can't log in -> give up.
                        raise LoginRejectedException()
            else:
                # The supplied password doesn't match our local records.  All
                # we can do is hope the password is accepted by the 3taps
                # Identity API, and if so accept the login.
                success,response = identity_api.login(username=user.username,
                                                      password=password)
                if success:
                    session = response
                    identity_api.logout(session)

                    salt = response['server_salt']
                    hash = hashlib.md5(password + salt).hexdigest()

                    user.uses_identity_api = True
                    user.identity_api_salt = salt
                    user.identity_api_hash = hash
                    user.save()
                else:
                    # We can't log in -> give up.
                    raise LoginRejectedException()
    elif phone_number != None and verification_code != None:
        phone_number = utils.format_phone_number(phone_number)
        try:
            user = User.objects.get(phone_number=phone_number,
                                    verification_code=verification_code)
        except User.DoesNotExist:
            raise LoginRejectedException()
        user.verified = True
        user.save()
    elif (user_id == None and username == None and password == None and
          phone_number == None and verification_code == None):
        # Create a new ad hoc user on-the-fly for this session.
        user = User()
        user.ad_hoc            = True
        user.username          = None
        user.password_salt     = None
        user.password_hash     = None
        user.phone_number      = None
        user.verification_code = None
        user.verified          = False
        user.created_at        = datetime.datetime.utcnow()
        user.updated_at        = datetime.datetime.utcnow()
        user.save()
    else:
        raise InvalidParametersException()

    return sessionHandler.create(user)
Esempio n. 12
0
def receive_sms(from_phone, to_phone, sms_message):
    """ Respond to an incoming SMS message from Twilio.

        'from_phone' is the phone number the SMS message was sent from,
        'to_phone' is the phone number the message was sent to, and
        'sms_message' is the text of the incoming SMS message.

        We process the SMS message, attempting to link it to an existing SMS
        channel so we can identify the recipient of the message.

        Upon completion, we return a string to use as a reply to send back to
        the 'from_phone', or None if no reply should be sent.

        Note that we raise an InvalidPhoneNumberException if either phone
        number cannot be parsed.
    """
    logger.debug('twilio.receive_sms(' +
                 'from_phone="%s", to_phone="%s", sms_message="%s")'
                 % (from_phone, to_phone, sms_message))

    # Convert the phone numbers to E.164 format.

    from_phone = utils.format_phone_number(from_phone)
    to_phone   = utils.format_phone_number(to_phone)

    # Find the User record associated with the sender's phone number.

    try:
        sender = User.objects.get(phone_number=from_phone)
    except User.DoesNotExist:
        return settings.SMS_TEXT_UNKNOWN_USER

    # Find an SMS channel which uses the phone number that the message was sent
    # to, and which was sending messages to the given user.

    possible_channels = TwilioSMSChannel.objects.filter(
                                phone_number__number=to_phone,
                                sender=sender)

    if len(possible_channels) == 0:
        return settings.SMS_TEXT_CONVERSATION_CLOSED
    if len(possible_channels) > 1:
        return settings.SMS_TEXT_UNABLE_TO_PROCESS_REPLY # Should never happen.

    found_channel = possible_channels[0]

    # If we get here, we've found the SMS channel that was sending messages to
    # this user.  This tells us the conversation this message was about, and
    # hence the topic.

    conversation = found_channel.conversation
    topic        = conversation.topic

    # If the conversation has been stopped, don't try to forward the reply.
    # Instead, return an appropriate message back to the sender.

    if conversation.stopped:
        return settings.SMS_TEXT_CONVERSATION_CLOSED

    # Calculate the recipient for the reply.  This is the other party in the
    # conversation.

    if sender == conversation.user_1:
        recipient = conversation.user_2
    else:
        recipient = conversation.user_1

    # If we're going to be forwarding this message via SMS, check that the
    # recipient hasn't reached their rate limit.

    if recipient.phone_number not in [None, ""] and recipient.verified:
        if not rateLimiter.is_phone_number_below_rate_limit(
                                                    recipient.phone_number):
            return settings.SMS_TEXT_RATE_LIMIT_EXCEEDED

    # Process the incoming SMS.

    from messageme.core.lib import messageHandler

    if not messageHandler.handle_special_message(sender, recipient, topic,
                                                 sms_message):
        # Pass an ordinary SMS message on to the recipient.
        msg = messageHandler.send_message(sender, recipient, topic, None,
                                          sms_message)

    return None # Don't send a message back to the 'from_phone' number.