Example #1
0
class CompleteProfileForm(form.EditForm):
    """ Implementation of the complete-profile form """

    fields = field.Fields(ICompleteProfile)
    id = 'CompleteProfileForm'
    label = _(u'heading_complete_profile', default=u'Complete your profile')
    description = _(u'description_complete_profile',
                    default=u'Please provide '
                    u'additional information about yourself.')

    ignoreContext = True

    def getContent(self):
        # XXX: Get member here?
        return self.context

    @button.buttonAndHandler(_(u'button_save', default=u'Save'), name=None)
    def handleSave(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        IStatusMessage(self.request).addStatusMessage(
            _(u'statusmessage_changes_saved', default=u'Changes saved'),
            'info')

    @button.buttonAndHandler(_(u'button_cancel', default=u'Cancel'),
                             name='cancel')
    def handleCancel(self, action):
        IStatusMessage(self.request).addStatusMessage(
            _(u'statusmessage_edit_cancelled', default=u'Edit cancelled'),
            'info')
Example #2
0
class ILogin(Interface):
    """ Login form schema """

    login = schema.TextLine(title=_(u'label_log_in', default=u'Log in'), )

    password = schema.Password(title=_(u'label_password',
                                       default=u'Password'), )
Example #3
0
    def updateWidgets(self):
        super(RegisterForm, self).updateWidgets(prefix='')
        portal_props = getToolByName(self.context, 'portal_properties')
        props = portal_props.site_properties
        use_email_as_login = props.getProperty('use_email_as_login')

        self.widgets['email'].tabindex = 1
        self.widgets['email'].autocapitalize = 'off'
        self.widgets['email'].placeholder = _(u'placeholder_email',
                                              default=u'Email address')
        append_klasses(self.widgets['email'], 'stretch')

        if not use_email_as_login:
            self.widgets['email'].tabindex += 1

            self.widgets['username'].tabindex = 1
            self.widgets['username'].autocapitalize = _(u'off')
            self.widgets['username'].placeholder = _(u'placeholder_username',
                                                     default=u'Username')
            append_klasses(self.widgets['username'], 'stretch')

        self.widgets['password'].tabindex = 3
        self.widgets['password'].placeholder = _(
            u'placeholder_password', default=u'Super secure password')
        append_klasses(self.widgets['password'], 'stretch')

        self.widgets['password_confirm'].tabindex = 4
        self.widgets['password_confirm'].placeholder = _(
            u'placeholder_password_confirm', default=u'Confirm password')
        append_klasses(self.widgets['password_confirm'], 'stretch')
Example #4
0
class LoginHelpForm(form.EditForm):
    ''' Implementation of the login help form '''

    subforms = []

    id = 'LoginHelpForm'
    label = _(u'heading_login_form_help', default=u'Need Help?')
    description = _(u'description_login_form_help',
                    default=u'Don\'t worry, I '
                    u'forget my password all the time.')

    ignoreContext = True

    def can_reset_password(self):
        # TODO: Actually check that the site allows reseting password
        return True

    def can_retrieve_username(self):
        # TODO: Actually check that the site allows retrieving the username
        return True

    def update(self):
        subforms = []
        # XXX: Not really sure how to handle the action and enctype vars
        if self.can_reset_password():
            form = RequestResetPassword(None, self.request)
            form.update()
            subforms.append(form)
        if self.can_retrieve_username():
            form = RequestUsername(None, self.request)
            form.update()
            subforms.append(form)

        self.subforms = subforms
        super(LoginHelpForm, self).update()
Example #5
0
    def updateWidgets(self):
        super(ResetPasswordForm, self).updateWidgets(prefix='')

        for idx, fn in enumerate(['password', 'password_confirm', ]):
            self.widgets[fn].tabindex = idx + 1
            append_klasses(self.widgets[fn], 'stretch')

        self.widgets['password'].placeholder = _(
            u'placeholder_password', default=u'Super secure password')

        self.widgets['password_confirm'].placeholder = _(
            u'placeholder_password_confirm', default=u'Confirm password')
Example #6
0
    def __call__(self):
        # Send request email
        if self.send_request_email():
            # Redirect back to insufficient privilege page.
            msg = _(u'Request sent.')
            msg_type = 'info'
        else:
            msg = _(u'Unable to send request.')
            msg_type = 'error'

        IStatusMessage(self.request).addStatusMessage(msg, type=msg_type)
        redirect_url = self.request.get('came_from')
        return self.request.response.redirect(redirect_url)
Example #7
0
    def handleLogin(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        membership_tool = getToolByName(self.context, 'portal_membership')
        if membership_tool.isAnonymousUser():
            self.request.response.expireCookie('__ac', path='/')
            email_login = getToolByName(self.context, 'portal_properties') \
                .site_properties.getProperty('use_email_as_login')
            if email_login:
                IStatusMessage(self.request).addStatusMessage(_(
                    u'Login failed. Both email address and password are case '
                    u'sensitive, check that caps lock is not enabled.'
                ), 'error')
            else:
                IStatusMessage(self.request).addStatusMessage(_(
                    u'Login failed. Both login name and password are case '
                    u'sensitive, check that caps lock is not enabled.'
                ), 'error')
            return

        member = membership_tool.getAuthenticatedMember()
        login_time = member.getProperty('login_time', '2000/01/01')
        if not isinstance(login_time, DateTime):
            login_time = DateTime(login_time)
        initial_login = login_time == DateTime('2000/01/01')
        if initial_login:
            # TODO: Redirect if this is initial login
            pass

        must_change_password = member.getProperty('must_change_password', 0)

        if must_change_password:
            # TODO: This user needs to change his password
            pass

        membership_tool.loginUser(self.request)

        IStatusMessage(self.request).addStatusMessage(_(
            u'statusmessage_logged_in', default=u'You are now logged in.'
        ), 'info')

        came_from = None
        if data['came_from']:
            came_from = data['came_from']

        self.redirect_after_login(came_from)
Example #8
0
 def handleResetPassword(self, action):
     # TODO: Send Email with password reset url
     IStatusMessage(self.request).addStatusMessage(
         _(u'statusmessage_pwreset_password_mail_sent',
           default=u'An '
           u'email has been sent with instructions on how to reset your '
           u'password.'), 'info')
Example #9
0
    def handleGetUsername(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        portal = getSite()
        pas = getToolByName(portal, 'acl_users')
        email = data['recover_username']
        results = pas.searchUsers(email=email, exact_match=True)
        send_email = True
        if not results:
            log.info('No user found for {0}'.format(email))
            send_email = False
        if len(results) > 1:
            log.info('More than one user found for {0}'.format(email))
            send_email = False
        if send_email:
            self.send_username(portal, results[0])

        # Paranoia Warning!
        # Same as with the reset-password form we don't want to allow
        # probing for email-adresses of existing users.
        # Because of this we always act as if that an email has been sent.
        # Instead we log the error-message.
        IStatusMessage(self.request).addStatusMessage(
            _(u'statusmessage_pwreset_username_mail_sent',
              default=u'An email has been sent with your username.'), 'info')
Example #10
0
 def ensureUsernameUnique(obj):
     site = api.portal.get()
     registration = getToolByName(site, 'portal_registration')
     if not registration.isMemberIdAllowed(obj.username):
         raise WidgetActionExecutionError('username', Invalid(
             _(u'error_username_alread_taken_or_invalid', default=u'Your '
               u'username is already in use or invalid.')))
Example #11
0
class ILoginSettings(Interface):
    """ Site settings for handling user registration and authentication """

    request_access_template = schema.Text(
        title=_(u'Request access template'),
        description=_(u'Email sent to content owners when a user requests '
                      u'access.'),
        required=True,
        default=_(u"""
From: "${user_fullname}" <${user_email}>
To: ${owner_emails}, ${manager_emails}
Subject: ${user_fullname} is requesting access to ${title}

${user_fullname} is requesting access to the page "${title}" at ${url}. \
Please visit the sharing controls at ${url}/@@sharing to the user with \
username ${user_id}."""))
Example #12
0
class ILoginFormSchema(Interface):
    """ Login form schema """

    ac_name = schema.TextLine(
        title=_(u'label_login_name', default=u'Login Name'),
        required=True,
    )

    ac_password = schema.Password(
        title=_(u'label_password', default=u'Password'),
        required=True,
    )

    came_from = schema.TextLine(
        title=u'Came From',  # not translated, hidden field
        required=False,
    )
Example #13
0
 def handleSave(self, action):
     data, errors = self.extractData()
     if errors:
         self.status = self.formErrorsMessage
         return
     IStatusMessage(self.request).addStatusMessage(_(
         u'statusmessage_changes_saved', default=u'Changes saved'
     ), 'info')
Example #14
0
 def handleSave(self, action):
     data, errors = self.extractData()
     if errors:
         self.status = self.formErrorsMessage
         return
     IStatusMessage(self.request).addStatusMessage(
         _(u'statusmessage_changes_saved', default=u'Changes saved'),
         'info')
Example #15
0
 def ensureValidPassword(obj):
     if obj.password != obj.password_confirm:
         raise WidgetActionExecutionError(
             'password',
             Invalid(
                 _(u'error_password_and_confirm_not_match',
                   default=u'Password '
                   u'and Confirm password do not match.')))
Example #16
0
    def handleLogin(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        membership_tool = getToolByName(self.context, 'portal_membership')
        status_msg = IStatusMessage(self.request)
        if membership_tool.isAnonymousUser():
            self.request.response.expireCookie('__ac', path='/')
            if self.use_email_as_login():
                status_msg.addStatusMessage(
                    _(u'Login failed. Both email address and password are '
                      u'case sensitive, check that caps lock is not enabled.'),
                    'error',
                )
            else:
                status_msg.addStatusMessage(
                    _(u'Login failed. Both login name and password are case '
                      u'sensitive, check that caps lock is not enabled.'),
                    'error',
                )
            return

        member = membership_tool.getAuthenticatedMember()
        must_change_password = member.getProperty('must_change_password', 0)
        login_time = member.getProperty('login_time', '2000/01/01')
        if not isinstance(login_time, DateTime):
            login_time = DateTime(login_time)
        is_initial_login = login_time == DateTime('2000/01/01')

        membership_tool.loginUser(self.request)
        status_msg.addStatusMessage(
            _(
                u'you_are_now_logged_in',
                default=u'Welcome! You are now logged in.',
            ), 'info')

        if is_initial_login:
            self.handle_initial_login()

        if must_change_password:
            self.force_password_change()

        came_from = data.get('came_from', None)
        self.redirect_after_login(came_from, is_initial_login)
Example #17
0
class ILoginHelpFormSchema(Interface):
    """ Login Help form schema """

    reset_password = schema.TextLine(
        title=_(u'label_pwreset_username', default=u'Username'),
        description=_(u'help_pwreset_username',
                      default=u'Enter your username '
                      u'or email and we’ll send you a password reset link.'),
        required=False,
    )

    recover_username = schema.TextLine(
        title=_(u'label_pwreset_email', default=u'Email'),
        description=_(u'help_pwreset_email',
                      default=u'Enter your email and '
                      u'we’ll send you your username.'),
        required=False,
    )
Example #18
0
class IRegisterFormSchema(Interface):
    """ Register form schema """

    username = schema.TextLine(
        title=_(u'label_username', default=u'Username'),
        required=True,
    )

    email = Email(
        title=_(u'label_email', default=u'Email'),
        required=True,
    )

    password = schema.Password(
        title=_(u'label_password', default=u'Password'),
        required=True,
    )

    password_confirm = schema.Password(
        title=_(u'label_password_confirm', default=u'Confirm password'),
        required=True,
    )

    @invariant
    def ensureUsernameUnique(obj):
        site = api.portal.get()
        registration = getToolByName(site, 'portal_registration')
        if not registration.isMemberIdAllowed(obj.username):
            raise WidgetActionExecutionError(
                'username',
                Invalid(
                    _(u'error_username_alread_taken_or_invalid',
                      default=u'Your '
                      u'username is already in use or invalid.')))

    @invariant
    def ensureValidPassword(obj):
        if obj.password != obj.password_confirm:
            raise WidgetActionExecutionError(
                'password',
                Invalid(
                    _(u'error_password_and_confirm_not_match',
                      default=u'Password '
                      u'and Confirm password do not match.')))
Example #19
0
 def ensureUsernameUnique(obj):
     site = api.portal.get()
     registration = getToolByName(site, 'portal_registration')
     if not registration.isMemberIdAllowed(obj.username):
         raise WidgetActionExecutionError(
             'username',
             Invalid(
                 _(u'error_username_alread_taken_or_invalid',
                   default=u'Your '
                   u'username is already in use or invalid.')))
Example #20
0
    def __call__(self):
        portal_state = getMultiAdapter(
            (self.context, self.request), name='plone_portal_state')

        if portal_state.anonymous():
            IStatusMessage(self.request).addStatusMessage(
                _(u'statusmessage_logged_out', default=u'You have been '
                  u'logged out.'), 'info')

            self.request.response.redirect(
                portal_state.navigation_root_url())
        else:
            return self.index()
Example #21
0
    def __call__(self):
        portal_state = getMultiAdapter((self.context, self.request),
                                       name='plone_portal_state')

        if portal_state.anonymous():
            IStatusMessage(self.request).addStatusMessage(
                _(u'statusmessage_logged_out',
                  default=u'You have been '
                  u'logged out.'), 'info')

            self.request.response.redirect(portal_state.navigation_root_url())
        else:
            return self.index()
Example #22
0
    def handlePasswordReset(self, action):

        authenticator = getMultiAdapter(
            (self.context, self.request), name=u'authenticator')
        if not authenticator.verify():
            raise Unauthorized
        data, errors = self.extractData()

        if errors:
            self.status = self.formErrorsMessage
            return

        if 'password' in data and 'password_confirm' in data:
            if data['password'] != data['password_confirm']:
                raise WidgetActionExecutionError('password', Invalid(_(
                    u'error_passwords_must_match', default=u'Passwords must '
                    u'match.')))

        current = api.user.get_current()

        # Try traverse subpath first:
        try:
            key = self.request['TraversalRequestNameStack'][:0]
        except IndexError:
            key = None

        # Fall back to request variable for BW compat
        if not key:
            key = self.request.get('key', None)

        pw_tool = getToolByName(self.context, 'portal_password_reset')
        # key is the value for arg randomstring
        pw_tool.resetPassword(current, key, data.get('password'))

        IStatusMessage(self.request).addStatusMessage(
            _(u'statusmessage_pwreset_passwort_was_reset', default=u'Your '
              u'password has been reset.'), 'info')

        self.request.response.redirect(self.context.absolute_url())
Example #23
0
class InitialLoginPasswordChange(PasswordPanel):
    def render(self):
        return self.index()

    @button.buttonAndHandler(
        _(u'label_change_password', default=u'Change Password'),
        name='reset_passwd',
    )
    def action_reset_passwd(self, action):
        super(InitialLoginPasswordChange,
              self).action_reset_passwd(self, action)
        if not action.form.widgets.errors:
            self.request.response.redirect(self.context.portal_url())
Example #24
0
class IResetPasswordFormSchema(Interface):
    """ reset password form schema """

    password = schema.Password(
        title=_(u'label_pwreset_password', default=u'Password'),
        required=True,
    )

    password_confirm = schema.Password(
        title=_(u'label_pwreset_confirm', default=u'Confirm password'),
        required=True,
    )

    @invariant
    def ensureValidPassword(obj):
        if obj.password != obj.password_confirm:
            raise WidgetActionExecutionError(
                'password',
                Invalid(
                    _(u'error_password_and_confirm_not_match',
                      default=u'Password '
                      u'and Confirm password do not match.')))
Example #25
0
class ForcedPasswordChange(PasswordPanel):
    def render(self):
        return self.index()

    @button.buttonAndHandler(
        _(u'label_change_password', default=u'Change Password'),
        name='reset_passwd',
    )
    def action_reset_passwd(self, action):
        super(ForcedPasswordChange, self).action_reset_passwd(self, action)
        if not action.form.widgets.errors:
            membership_tool = getToolByName(self.context, 'portal_membership')
            member = membership_tool.getAuthenticatedMember()
            member.setProperties(must_change_password=0)
            self.request.response.redirect(self.context.portal_url())
Example #26
0
class RequestResetPassword(form.Form):

    id = 'RequestResetPassword'
    label = u''
    fields = field.Fields(ILoginHelpFormSchema).select('reset_password')
    ignoreContext = True

    render = ViewPageTemplateFile('templates/subform_render.pt')

    def updateWidgets(self):
        super(RequestResetPassword, self).updateWidgets()
        if self.use_email_as_login():
            self.widgets['reset_password'].label = _(u'label_email',
                                                     default=u'Email')

    @button.buttonAndHandler(_(u'button_pwreset_reset_password',
                               default=u'Reset your password'),
                             name='reset')
    def handleResetPassword(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        portal = getSite()
        regtool = getToolByName(portal, 'portal_registration')
        try:
            regtool.mailPassword(data['reset_password'], self.request)
        except ValueError as e:
            # Paranoia Warning!
            # We act as if a message has been sent to prevent probing Plone
            # for valid loginnames. Instead we log the error-message.
            log.info(
                'Error while trying to send a reset-password notice to user {0}: {1}'
                .format(data['reset_password'], e))  # noqa: E501
            pass

        IStatusMessage(self.request).addStatusMessage(
            _(u'statusmessage_pwreset_password_mail_sent',
              default=u'An '
              u'email has been sent with instructions on how to reset your '
              u'password.'), 'info')

    def use_email_as_login(self):
        registry = getUtility(IRegistry)
        security_settings = registry.forInterface(ISecuritySchema,
                                                  prefix='plone')
        return security_settings.use_email_as_login
Example #27
0
class RequestResetPassword(form.Form):

    id = 'RequestResetPassword'
    label = u''
    fields = field.Fields(ILoginHelpFormSchema).select('reset_password')
    ignoreContext = True

    render = ViewPageTemplateFile('templates/subform_render.pt')

    @button.buttonAndHandler(_(u'button_pwreset_reset_password',
                               default=u'Reset your password'),
                             name='reset')
    def handleResetPassword(self, action):
        # TODO: Send Email with password reset url
        IStatusMessage(self.request).addStatusMessage(
            _(u'statusmessage_pwreset_password_mail_sent',
              default=u'An '
              u'email has been sent with instructions on how to reset your '
              u'password.'), 'info')
Example #28
0
class RequestUsername(form.Form):

    id = 'RequestUsername'
    label = u''
    fields = field.Fields(ILoginHelpFormSchema).select('recover_username')
    ignoreContext = True

    render = ViewPageTemplateFile('templates/subform_render.pt')

    # TODO: Add validation to the field to check that is a proper email

    @button.buttonAndHandler(_(u'button_pwreset_get_username',
                               default='Get your username'),
                             name='get_username')
    def handleGetUsername(self, action):
        # TODO: Send Email with username
        IStatusMessage(self.request).addStatusMessage(
            _(u'statusmessage_pwreset_username_mail_sent',
              default=u'An '
              u'email has been sent with your username.'), 'info')
Example #29
0
    def updateWidgets(self):
        auth = self._get_auth()

        if auth:
            fieldname_name = auth.get('name_cookie', '__ac_name')
            fieldname_password = auth.get('pw_cookie', '__ac_password')
        else:
            fieldname_name = '__ac_name'
            fieldname_password = '******'

        self.fields['ac_name'].__name__ = fieldname_name
        self.fields['ac_password'].__name__ = fieldname_password

        super(LoginForm, self).updateWidgets(prefix='')

        if self.use_email_as_login():
            self.widgets[fieldname_name].label = _(u'label_email',
                                                   default=u'Email')
        self.widgets['came_from'].mode = HIDDEN_MODE
        self.widgets['came_from'].value = self.get_came_from()
Example #30
0
class LoginHelpForm(form.EditForm):
    ''' Implementation of the login help form '''

    subforms = []

    id = 'LoginHelpForm'
    label = _(u'heading_login_form_help', default=u'Need Help?')

    ignoreContext = True

    def render(self):
        return self.index()

    def can_reset_password(self):
        # TODO: Actually check that the site allows reseting password
        return True

    def can_retrieve_username(self):
        # TODO: Actually check that the site allows retrieving the username
        return True

    def update(self):
        subforms = []
        # XXX: Not really sure how to handle the action and enctype vars
        if self.can_reset_password():
            form = RequestResetPassword(None, self.request)
            form.update()
            subforms.append(form)
        if not self.use_email_as_login() and self.can_retrieve_username():
            form = RequestUsername(None, self.request)
            form.update()
            subforms.append(form)

        self.subforms = subforms
        super(LoginHelpForm, self).update()

    def use_email_as_login(self):
        registry = getUtility(IRegistry)
        security_settings = registry.forInterface(ISecuritySchema,
                                                  prefix='plone')
        return security_settings.use_email_as_login
Example #31
0
    def send_username(self, portal, userinfo):
        registry = getUtility(IRegistry)
        encoding = registry.get('plone.email_charset', 'utf-8')
        translated_template = translate(
            SEND_USERNAME_TEMPLATE,
            context=self.request,
        )

        mail_text = translated_template.format(
            email=userinfo['email'],
            portal_url=portal.absolute_url(),
            fullname=userinfo['title'],
            login=userinfo['login'],
            email_from_name=registry['plone.email_from_name'],
            encoded_mail_sender=self.encoded_mail_sender(),
        )
        # The mail headers are not properly encoded we need to extract
        # them and let MailHost manage the encoding.
        if isinstance(mail_text, unicode):
            mail_text = mail_text.encode(encoding)
        message_obj = message_from_string(mail_text.strip())
        subject = message_obj['Subject']
        m_to = message_obj['To']
        m_from = message_obj['From']
        msg_type = message_obj.get('Content-Type', 'text/plain')

        host = getToolByName(portal, 'MailHost')
        try:
            host.send(mail_text,
                      m_to,
                      m_from,
                      subject=subject,
                      charset=encoding,
                      immediate=True,
                      msg_type=msg_type)
        except SMTPRecipientsRefused:
            # Don't disclose email address on failure
            raise SMTPRecipientsRefused(
                _(u'Recipient address rejected by server.'))
        except SMTPException as e:
            raise (e)
Example #32
0
    def handleResetPassword(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        portal = getSite()
        regtool = getToolByName(portal, 'portal_registration')
        try:
            regtool.mailPassword(data['reset_password'], self.request)
        except ValueError as e:
            # Paranoia Warning!
            # We act as if a message has been sent to prevent probing Plone
            # for valid loginnames. Instead we log the error-message.
            log.info(
                'Error while trying to send a reset-password notice to user {0}: {1}'
                .format(data['reset_password'], e))  # noqa: E501
            pass

        IStatusMessage(self.request).addStatusMessage(
            _(u'statusmessage_pwreset_password_mail_sent',
              default=u'An '
              u'email has been sent with instructions on how to reset your '
              u'password.'), 'info')
Example #33
0
class ICompleteProfile(Interface):
    """ Temporary schema used in the complete-profile view """

    first_name = schema.TextLine(
        title=_(u'First Name'),
        description=_(u'Please provide your first name.'),
        required=True,
    )

    last_name = schema.TextLine(
        title=_(u'Last Name'),
        description=_(u'Please provide your last name.'),
        required=True,
    )

    bio = schema.Text(
        title=_(u'Bio'),
        description=_(u'Please provide a bio of yourself.'),
        required=False,
    )
Example #34
0
 def handleCancel(self, action):
     IStatusMessage(self.request).addStatusMessage(_(
         u'statusmessage_edit_cancelled', default=u'Edit cancelled'
     ), 'info')
Example #35
0
 def ensureValidPassword(obj):
     if obj.password != obj.password_confirm:
         raise WidgetActionExecutionError('password', Invalid(_(
             u'error_password_and_confirm_not_match', default=u'Password '
             u'and Confirm password do not match.')))
Example #36
0
 def handleGetUsername(self, action):
     # TODO: Send Email with username
     IStatusMessage(self.request).addStatusMessage(
         _(u'statusmessage_pwreset_username_mail_sent', default=u'An '
           u'email has been sent with your username.'), 'info')
Example #37
0
 def handleResetPassword(self, action):
     # TODO: Send Email with password reset url
     IStatusMessage(self.request).addStatusMessage(
         _(u'statusmessage_pwreset_password_mail_sent', default=u'An '
           u'email has been sent with instructions on how to reset your '
           u'password.'), 'info')