[#10288] ticket:784 Block project registrations using a T7 country phone number
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 197f859..1134284 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -199,7 +199,7 @@
@expose('json:')
def verify_phone(self, number):
p = plugin.ProjectRegistrationProvider.get()
- result = p.verify_phone(c.user, number)
+ result = p.verify_phone(c.user, number, request)
request_id = result.pop('request_id', None)
if request_id:
session['phone_verification.request_id'] = request_id
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index abb5c8c..d71a9f8 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -732,11 +732,22 @@
return True
return bool(user.get_tool_data('phone_verification', 'number_hash'))
- def verify_phone(self, user, number):
+ def verify_phone(self, user, number, req):
ok = {'status': 'ok'}
if not asbool(config.get('project.verify_phone')):
return ok
number = utils.clean_phone_number(number)
+ blocked_prefix = self.t7_phone(number)
+ if blocked_prefix:
+ log.info(
+ 'Blocked project registation, phone number is in T7 list. '
+ 'User: %s, Phone # hash: %s, Country code: %s, IP: %s, UA: %s',
+ user.username,
+ utils.phone_number_hash(number),
+ blocked_prefix,
+ utils.ip_address(req),
+ req.headers.get('User-Agent'))
+ return {'status': 'error', 'error': 'T7_BLOCKED'}
return g.phone_service.verify(number)
def check_phone_verification(self, user, request_id, pin, number_hash):
@@ -753,6 +764,13 @@
h.auditlog_user(msg, user=user)
return res
+ def t7_phone(self, number):
+ t7_prefixes = json.loads(config.get('phone.t7_prefixes', '[]'))
+ for p in t7_prefixes:
+ if number.startswith(p):
+ return p
+ return None
+
def register_neighborhood_project(self, neighborhood, users, allow_register=False):
from allura import model as M
shortname = '--init--'
diff --git a/Allura/allura/nf/allura/css/allura.css b/Allura/allura/nf/allura/css/allura.css
index 6c5c1f4..c89a02c 100644
--- a/Allura/allura/nf/allura/css/allura.css
+++ b/Allura/allura/nf/allura/css/allura.css
@@ -85,5 +85,5 @@
}
#phone_verification_overlay iframe {
- height: 250px;
+ height: 280px;
}
diff --git a/Allura/allura/public/nf/js/phone-verification.js b/Allura/allura/public/nf/js/phone-verification.js
index e6bb8fc..71b5744 100644
--- a/Allura/allura/public/nf/js/phone-verification.js
+++ b/Allura/allura/public/nf/js/phone-verification.js
@@ -71,13 +71,27 @@
disabled: this.isButtonDisabled()
};
var nbsp = String.fromCharCode(160);
+ var error = this.getError(this.props.state.error);
return dom('div', null,
dom('label', {className: grid}, this.getLabel()),
dom('input', input_props),
- dom('div', {className: grid + ' error-text'}, this.props.state.error || nbsp),
+ dom('div', {className: grid + ' error-text'}, error || nbsp),
dom('div', {className: grid},
dom('button', button_props, 'Submit')));
},
+
+ getError: function(error) {
+ if (error === 'T7_BLOCKED') {
+ var error_text = 'Your request is being denied as it appears the phone ' +
+ 'number provided is from a location banned by our ';
+ var link_attrs = {href: 'http://slashdotmedia.com/terms-of-use',
+ target: '_blank'};
+ var error_link = dom('a', link_attrs, 'Terms of Use');
+ return dom('span', null, [error_text, error_link]);
+ } else {
+ return error;
+ }
+ },
handleClick: function() {
if (!this.isButtonDisabled()) {
diff --git a/Allura/allura/tests/test_plugin.py b/Allura/allura/tests/test_plugin.py
index 64b9695..94cbeef 100644
--- a/Allura/allura/tests/test_plugin.py
+++ b/Allura/allura/tests/test_plugin.py
@@ -89,6 +89,7 @@
class UserMock(object):
def __init__(self):
+ self.username = 'test-user'
self.tool_data = {}
self._projects = []
@@ -144,18 +145,45 @@
def test_verify_phone_disabled(self, g):
g.phone_service = Mock(spec=phone.PhoneService)
with h.push_config(tg.config, **{'project.verify_phone': 'false'}):
- result = self.p.verify_phone(self.user, '12345')
+ result = self.p.verify_phone(self.user, '12345', None)
assert_false(g.phone_service.verify.called)
assert_equal(result, {'status': 'ok'})
+ @patch.object(plugin, 'log', autospec=True)
+ @patch.object(plugin, 'g', autospec=True)
+ def test_verify_phone_blocked(self, g, log):
+ g.phone_service = Mock(spec=phone.PhoneService)
+ cfg = {'project.verify_phone': 'true',
+ 'phone.t7_prefixes': '["13", "74"]'}
+ with h.push_config(tg.config, **cfg):
+ req = Request.blank('/')
+ req.remote_addr = '1.2.3.4'
+ req.headers['User-Agent'] = 'Chrome'
+ result = self.p.verify_phone(self.user, '13-21-94', req)
+ assert_false(g.phone_service.verify.called)
+ assert_equal(result, {'status': 'error', 'error': 'T7_BLOCKED'})
+ log.info.assert_called_once_with(
+ 'Blocked project registation, phone number is in T7 list. '
+ 'User: %s, Phone # hash: %s, Country code: %s, IP: %s, UA: %s',
+ 'test-user', '43648c7bc5f0fe67466d174876a9ccdf7a84f8c4',
+ '13', '1.2.3.4', 'Chrome')
+
@patch.object(plugin, 'g')
def test_verify_phone(self, g):
g.phone_service = Mock(spec=phone.PhoneService)
with h.push_config(tg.config, **{'project.verify_phone': 'true'}):
- result = self.p.verify_phone(self.user, '123 45 45')
+ result = self.p.verify_phone(self.user, '123 45 45', None)
g.phone_service.verify.assert_called_once_with('1234545')
assert_equal(result, g.phone_service.verify.return_value)
+ def test_t7_phone(self):
+ cfg = {'phone.t7_prefixes': '["13", "74"]'}
+ with h.push_config(tg.config, **cfg):
+ assert_equal(self.p.t7_phone('13 01 24'), '13')
+ assert_equal(self.p.t7_phone('74010203'), '74')
+ assert_equal(self.p.t7_phone('555-555-5555'), None)
+ assert_equal(self.p.t7_phone('38 093 111 11 11'), None)
+
@patch.object(plugin, 'g')
def test_check_phone_verification_disabled(self, g):
g.phone_service = Mock(spec=phone.PhoneService)