Commit 787e2a48 authored by Abhilash Raj's avatar Abhilash Raj

Merge branch 'encode-regex' into 'master'

Always quote special characters in emails when used in URL.

Closes #44

See merge request !93
parents 2ed26a89 bc1452e0
Pipeline #51157412 passed with stage
in 4 minutes and 46 seconds
......@@ -7,6 +7,7 @@ NEWS for mailmanclient
* Add a ``mail_host`` parameter to ``get_list_page`` and ``find_lists`` to
support filtering the response by a list domain.
* URL encode values in URL which are url unsafe. (Closes #44)
3.2.2 (2019-02-09)
......
......@@ -13,6 +13,9 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with mailmanclient. If not, see <http://www.gnu.org/licenses/>.
from urllib.parse import quote_plus
from mailmanclient.restobjects.preferences import PreferencesMixin
from mailmanclient.restbase.base import RESTList, RESTObject
......@@ -70,10 +73,14 @@ class Address(RESTObject, PreferencesMixin):
def verify(self):
self._connection.call(
'addresses/{0}/verify'.format(self.email), method='POST')
'addresses/{0}/verify'.format(quote_plus(self.email)),
method='POST',
)
self._reset_cache()
def unverify(self):
self._connection.call(
'addresses/{0}/unverify'.format(self.email), method='POST')
'addresses/{0}/unverify'.format(quote_plus(self.email)),
method='POST'
)
self._reset_cache()
......@@ -13,7 +13,9 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with mailmanclient. If not, see <http://www.gnu.org/licenses/>.
from urllib.error import HTTPError
from urllib.parse import quote_plus
from mailmanclient.restobjects.mailinglist import MailingList
from mailmanclient.restbase.base import RESTList, RESTObject
......@@ -57,7 +59,7 @@ class Bans(RESTList):
# Avoid getting the whole list just to check membership
try:
response, content = self._connection.call(
'{}/{}'.format(self._url, item))
'{}/{}'.format(self._url, quote_plus(item)))
except HTTPError as e:
if e.code == 404:
return False
......
......@@ -16,7 +16,7 @@
import warnings
from operator import itemgetter
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.parse import urlencode, quote_plus
from mailmanclient.restobjects.header_match import HeaderMatches
from mailmanclient.restobjects.archivers import ListArchivers
......@@ -187,7 +187,8 @@ class MailingList(RESTObject):
self.remove_role('moderator', address)
def remove_role(self, role, address):
url = 'lists/%s/%s/%s' % (self.fqdn_listname, role, address)
url = 'lists/%s/%s/%s' % (
self.fqdn_listname, role, quote_plus(address))
self._connection.call(url, method='DELETE')
def moderate_message(self, request_id, action):
......@@ -265,7 +266,8 @@ class MailingList(RESTObject):
# the member. Incase there is no matching subscription, an
# HTTPError is returned instead.
try:
path = 'lists/{0}/member/{1}'.format(self.list_id, email)
path = 'lists/{0}/member/{1}'.format(
self.list_id, quote_plus(email))
response, content = self._connection.call(path)
return Member(self._connection, content['self_link'], content)
except HTTPError:
......
......@@ -14,8 +14,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with mailmanclient. If not, see <http://www.gnu.org/licenses/>.
from mailmanclient.restobjects.preferences import PreferencesMixin
from mailmanclient.restobjects.preferences import PreferencesMixin
from mailmanclient.restobjects.address import Addresses, Address
from mailmanclient.restbase.base import RESTObject
......
# Copyright (C) 2019 by the Free Software Foundation, Inc.
#
# This file is part of mailman.client.
#
# mailman.client is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, version 3 of the License.
#
# mailman.client is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with mailman.client. If not, see <http://www.gnu.org/licenses/>.
"""Test for the general Client specific behavior.."""
import unittest
from mailmanclient import Client
from urllib.error import HTTPError
class TestUrlencodedPaths(unittest.TestCase):
"""Test that paths are always safe"""
def setUp(self):
self._client = Client(
'http://localhost:9001/3.1', 'restadmin', 'restpass')
self.domain = self._client.create_domain('example.org')
def tearDown(self):
self.domain.delete()
def test_bans_paths_are_urlencoded_when_needed(self):
# Test that we can ban regular expressions.
self._client.bans.add('^[email protected]')
bans = self._client.bans
self.assertEqual(len(bans), 1)
# This should actually call the URL and should return True.
self.assertIn('^[email protected]', self._client.bans)
def test_member_paths_are_urlencoded(self):
mlist = self.domain.create_list('other')
mlist.subscribe('[email protected]',
pre_verified=True,
pre_confirmed=True,
pre_approved=True)
# Make sure that member exists.
self.assertEqual(len(mlist.members), 1)
# Let's see if we can get the member resource. This will
try:
member = mlist.get_member('[email protected]')
self.assertIsNotNone(member)
except HTTPError:
self.fail('Unexpected HTTPError.')
def test_non_member_paths_are_urlencoded(self):
mlist = self.domain.create_list('some')
mlist.add_role(address='[email protected]', role='moderator')
# Now, this shouldn't raise 404 error.
try:
mlist.remove_role(
address='[email protected]', role='moderator')
except HTTPError:
self.fail('Unexpected HTTPError.')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment