Skip to content

Commit

Permalink
Merge pull request #966 from jookies/0.10
Browse files Browse the repository at this point in the history
0.10.9
  • Loading branch information
farirat committed Feb 25, 2021
2 parents d7de31d + 576bf09 commit 16c5426
Show file tree
Hide file tree
Showing 18 changed files with 244 additions and 96 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ python:
- '3.8'
- '3.9'
env:
- ROOT_PATH=~/jasmin JASMIN_RELEASE=0.10.8
- ROOT_PATH=~/jasmin JASMIN_RELEASE=0.10.9
# Command to install dependencies
install:
- pip install -r requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion jasmin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

MAJOR = 0
MINOR = 10
PATCH = 8
PATCH = 9
META = ''


Expand Down
4 changes: 4 additions & 0 deletions jasmin/protocols/cli/usersm.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,10 @@ def show(self, arg, opts):
sectionValue = sectionValue.pattern
elif section == 'Quota' and sectionValue is None:
sectionValue = 'ND'

# Decode binary data to string for display purpose
if isinstance(sectionValue, bytes):
sectionValue = sectionValue.decode()
self.protocol.sendData('%s %s %s %s' % (
key, section.lower(), SectionShortKey, sectionValue), prompt=False)
if value['class'] == 'SmppsCredential':
Expand Down
86 changes: 47 additions & 39 deletions jasmin/protocols/http/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
HTTP request validators
"""

import re
from jasmin.protocols.http.errors import UrlArgsValidationError, CredentialValidationError
from jasmin.protocols.validation import AbstractCredentialValidator

Expand Down Expand Up @@ -116,35 +117,57 @@ def _checkRateAuthorizations(self):
raise CredentialValidationError(
'Authorization failed for user [%s] (Cannot check rate).' % self.user)

def _get_binary_r(self, key, credential=None):
"Return a compile re object with a binary pattern"
if credential is None:
credential = self.user.mt_credential

r = credential.getValueFilter(key)
if isinstance(r.pattern, str):
r = re.compile(r.pattern.encode())

return r

def _checkSendFilters(self):
"""MT Filters check"""

if (self.user.mt_credential.getValueFilter('destination_address') is None or
not self.user.mt_credential.getValueFilter('destination_address').match(
self._convert_to_string(b'to'))):
# Filtering destination_address
_value = self.request.args[b'to'][0]
_r = self._get_binary_r('destination_address')
if _r is None or (_r.pattern != b'.*' and not _r.match(_value)):
raise CredentialValidationError(
'Value filter failed for user [%s] (destination_address filter mismatch).' % self.user)
if b'from' in self.request.args and (self.user.mt_credential.getValueFilter('source_address') is None or
not self.user.mt_credential.getValueFilter('source_address').match(
self._convert_to_string(b'from'))):
raise CredentialValidationError(
'Value filter failed for user [%s] (source_address filter mismatch).' % self.user)
if b'priority' in self.request.args and (self.user.mt_credential.getValueFilter('priority') is None or
not self.user.mt_credential.getValueFilter('priority').match(
self._convert_to_string(b'priority'))):
raise CredentialValidationError(
'Value filter failed for user [%s] (priority filter mismatch).' % self.user)
if b'validity-period' in self.request.args and (
self.user.mt_credential.getValueFilter('validity_period') is None or
not self.user.mt_credential.getValueFilter('validity_period').match(
self._convert_to_string(b'validity-period'))):
raise CredentialValidationError(
'Value filter failed for user [%s] (validity_period filter mismatch).' % self.user)
if (b'content' in self.request.args and
(self.user.mt_credential.getValueFilter('content') is None or
not self.user.mt_credential.getValueFilter('content').match(self._convert_to_string(b'content', self.request.args.get(b'coding', [None])[0])))):
raise CredentialValidationError(
'Value filter failed for user [%s] (content filter mismatch).' % self.user)

# Filtering source_address
if b'from' in self.request.args:
_value = self.request.args[b'from'][0]
_r = self._get_binary_r('source_address')
if _r is None or (_r.pattern != b'.*' and not _r.match(_value)):
raise CredentialValidationError(
'Value filter failed for user [%s] (source_address filter mismatch).' % self.user)

# Filtering priority
if b'priority' in self.request.args:
_value = self.request.args[b'priority'][0]
_r = self._get_binary_r('priority')
if _r is None or (_r.pattern != b'^[0-3]$' and not _r.match(_value)):
raise CredentialValidationError(
'Value filter failed for user [%s] (priority filter mismatch).' % self.user)

# Filtering validity_period
if b'validity-period' in self.request.args:
_value = self.request.args[b'validity-period'][0]
_r = self._get_binary_r('validity_period')
if not isinstance(_value, int) and (_r is None or (_r.pattern != b'.*' and not _r.match(_value))):
raise CredentialValidationError(
'Value filter failed for user [%s] (validity_period filter mismatch).' % self.user)

if b'content' in self.request.args:
_value = self.request.args[b'content'][0]
_r = self._get_binary_r('content')
if _r is None or (_r.pattern != b'.*' and not _r.match(_value)):
raise CredentialValidationError(
'Value filter failed for user [%s] (content filter mismatch).' % self.user)

def updatePDUWithUserDefaults(self, PDU):
"""Will update SubmitSmPDU.params from User credential defaults whenever a
Expand All @@ -168,18 +191,3 @@ def validate(self):
self._checkBalanceAuthorizations()
else:
raise CredentialValidationError('Unknown action [%s].' % self.action)

def _convert_to_string(self, arg_name, encoding_type=None):
value = self.request.args[arg_name][0]
if isinstance(value, bytes):
if encoding_type == b'13':
# JISX0212 can be decoded this way given the escape sequences
return (b'\x1b$(D' + value + b'\x1b(B').decode('iso2022jp-1')
if encoding_type in (b'2', b'4', b'14'):
# These types dont decode properly
return ''
return value.decode(self.encoding_map.get(encoding_type, 'ascii'))
if isinstance(value, str):
return value
return str(value)

8 changes: 4 additions & 4 deletions jasmin/protocols/rest/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@ class JasminHttpApiProxy:

def call_jasmin(self, url, params=None):
try:
print(old_api_uri, url)
print(params)
r = requests.get('%s/%s' % (old_api_uri, url), params=params)
except requests.exceptions.ConnectionError as e:
raise HTTPInternalServerError('Jasmin httpapi connection error',
'Could not connect to Jasmin http api (%s): %s' % (old_api_uri, e))
except Exception as e:
raise HTTPInternalServerError('Jasmin httpapi unknown error', str(e))
else:
print(r.content)
return r.status_code, r.content.decode('utf-8').strip('"')


Expand Down Expand Up @@ -108,9 +105,12 @@ def on_get(self, request, response):

# Convert _ to -
# Added for compliance with json encoding/decoding constraints on dev env like .Net
for k, v in request_args.items():
_request_args = request_args.copy() # void dictionary key change error in python 3.8
for k, v in _request_args.items():
del (request_args[k])
request_args[re.sub('_', '-', k)] = v

del _request_args # Unset the variable

self.build_response_from_proxy_result(
response,
Expand Down
4 changes: 3 additions & 1 deletion jasmin/protocols/smpp/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,9 @@ def addInterceptorPBClient(self, interceptorpb_client):
self.log.info('Added Interceptor to SMPPServerFactory')

def submit_sm_event_interceptor(self, system_id, *args):
"Intercept submit_sm befor handing it to self.submit_sm_event"
"""Intercept submit_sm before handing it to self.submit_sm_event
"""

self.log.debug('Intercepting submit_sm event for system_id: %s', system_id)

# Args validation
Expand Down
10 changes: 8 additions & 2 deletions jasmin/protocols/smpp/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def __init__(self, config=None, long_content_max_parts=5, long_content_split='sa
else:
self.config = SMPPClientConfig(**{'id': 'anyid'})

self.long_content_max_parts = long_content_max_parts
self.long_content_max_parts = int(long_content_max_parts)
if isinstance(long_content_split, bytes):
long_content_split = long_content_split.decode()
self.long_content_split = long_content_split
Expand Down Expand Up @@ -307,4 +307,10 @@ def getReceipt(self, dlr_pdu, msgid, source_addr, destination_addr, message_stat
def get_enum(self, enum_type, value):
if isinstance(value, Enum):
return value
return getattr(enum_type, value.lstrip(str(enum_type) + '.'))

_value = value.split('.')

if len(_value) == 2:
return getattr(enum_type, _value[1])
else:
return getattr(enum_type, value)
59 changes: 33 additions & 26 deletions jasmin/protocols/smpp/validation.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"""
SMPP validators
"""
import re
from enum import Enum

from jasmin.protocols.validation import AbstractCredentialValidator
from jasmin.protocols.smpp.error import *
from smpp.pdu.constants import priority_flag_value_map
from smpp.pdu.constants import priority_flag_value_map, priority_flag_name_map
from smpp.pdu.pdu_types import RegisteredDeliveryReceipt, RegisteredDelivery


Expand Down Expand Up @@ -33,34 +33,52 @@ def _checkSendAuthorizations(self):
raise AuthorizationError(
'Authorization failed for username [%s] (Setting source address is not authorized).' % self.user)
if (not self.user.mt_credential.getAuthorization('set_priority') and
self._convert_to_string('priority_flag') != priority_flag_value_map[0]):
self.submit_sm.params['priority_flag'] != priority_flag_value_map[0]):
raise AuthorizationError(
'Authorization failed for username [%s] (Setting priority is not authorized).' % self.user)

def _get_binary_r(self, key, credential=None):
"Return a compile re object with a binary pattern"
if credential is None:
credential = self.user.mt_credential

r = credential.getValueFilter(key)
if isinstance(r.pattern, str):
r = re.compile(r.pattern.encode())

return r

def _checkSendFilters(self):
"""MT Filters check"""

if (self.user.mt_credential.getValueFilter('destination_address') is None or
not self.user.mt_credential.getValueFilter('destination_address').match(
self._convert_to_string('destination_addr'))):
# Filtering destination_address
_value = self.submit_sm.params['destination_addr']
_r = self._get_binary_r('destination_address')
if _r is None or (_r.pattern != b'.*' and not _r.match(_value)):
raise FilterError(
'Value filter failed for username [%s] (destination_address filter mismatch).' % self.user,
'destination_address')
if (self.user.mt_credential.getValueFilter('source_address') is None or
not self.user.mt_credential.getValueFilter('source_address').match(
self._convert_to_string('source_addr'))):

# Filtering source_address
_value = self.submit_sm.params['source_addr']
_r = self._get_binary_r('source_address')
if _r is None or (_r.pattern != b'.*' and not _r.match(_value)):
raise FilterError(
'Value filter failed for username [%s] (source_address filter mismatch).' % self.user,
'source_address')
if (self.user.mt_credential.getValueFilter('priority') is None or
not self.user.mt_credential.getValueFilter('priority').match(
self._convert_to_string('priority_flag'))):

# Filtering priority_flag
_value = ('%s' % priority_flag_name_map[self.submit_sm.params['priority_flag'].name]).encode()
_r = self._get_binary_r('priority')
if _r is None or (_r.pattern != b'^[0-3]$' and not _r.match(_value)):
raise FilterError(
'Value filter failed for username [%s] (priority filter mismatch).' % self.user,
'priority')
if (self.user.mt_credential.getValueFilter('content') is None or
not self.user.mt_credential.getValueFilter('content').match(
self._convert_to_string('short_message'))):

# Filtering content
_value = self.submit_sm.params['short_message']
_r = self._get_binary_r('content')
if _r is None or (_r.pattern != b'.*' and not _r.match(_value)):
raise FilterError(
'Value filter failed for username [%s] (content filter mismatch).' % self.user,
'content')
Expand All @@ -83,14 +101,3 @@ def validate(self):
self._checkSendFilters()
else:
raise CredentialValidationError('Unknown action [%s].' % self.action)

def _convert_to_string(self, arg_name):
value = self.submit_sm.params[arg_name]
if isinstance(value, bytes):
return value.decode()
if isinstance(value, str):
return value
if isinstance(value, Enum):
# this is likely priority flag and we need the value minus one
return str(value._value_-1)
return str(value)
10 changes: 5 additions & 5 deletions jasmin/routing/jasminApi.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ def __init__(self, default_authorizations=True):
}

self.value_filters = {
'destination_address': re.compile(r'.*'),
'source_address': re.compile(r'.*'),
'priority': re.compile(r'^[0-3]$'),
'validity_period': re.compile(r'^\d+$'),
'content': re.compile(r'.*'),
'destination_address': re.compile(b'.*'),
'source_address': re.compile(b'.*'),
'priority': re.compile(b'^[0-3]$'),
'validity_period': re.compile(b'^\d+$'),
'content': re.compile(b'.*'),
}

self.defaults = {'source_address': None, }
Expand Down
22 changes: 22 additions & 0 deletions jasmin/tools/migrations/migration.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
from jasmin.routing.Filters import TagFilter
from jasmin.routing.jasminApi import User, Group

Expand Down Expand Up @@ -109,6 +110,24 @@ def fix_users_09rc24(data, context=None):

return new_data

def fix_user_filters_0109(data, context=None):
"""Set regex filters to binary format"""

if context == 'users':
# Convert regex patterns from str to bytes
new_data = []
for user in data:
for key in user.mt_credential.value_filters.keys():
pattern = user.mt_credential.value_filters[key].pattern

if not isinstance(pattern, bytes):
bpattern = pattern.encode()
user.mt_credential.value_filters[key] = re.compile(bpattern)

new_data.append(user)

return new_data


"""This is the main map for orchestrating config migrations.
Expand All @@ -134,4 +153,7 @@ def fix_users_09rc24(data, context=None):
{'conditions': ['<=0.9023'],
'contexts': {'users'},
'operations': [fix_users_09rc24]},
{'conditions': ['<=0.10008'],
'contexts': {'users'},
'operations': [fix_user_filters_0109]},
]
2 changes: 1 addition & 1 deletion misc/doc/sources/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
# The short X.Y version.
version = "0.10"
# The full version, including alpha/beta/rc tags.
release = "0.10.8"
release = "0.10.9"

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
2 changes: 1 addition & 1 deletion nfpm.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: "jasmin-sms-gateway"
arch: "amd64"
platform: "linux"
version: "v0.10.8"
version: "v0.10.9"
section: "default"
priority: "extra"
maintainer: "Jookies LTD <jasmin@jookies.net>"
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def parse_requirements(filename):

setup(
name="jasmin",
version='0.10.8',
version='0.10.9',
author="Jookies LTD",
author_email="jasmin@jookies.net",
url="https://www.jasminsms.com",
Expand Down

0 comments on commit 16c5426

Please sign in to comment.