Commit f506bce7 authored by Artem Baldin's avatar Artem Baldin
Browse files

fix: add init point value validation

parent 0a483638
# WebSocket close codes
| Close code (uint16) | Codename | Internal | Customizable | Description |
|---------------------|------------------------|----------|--------------|-------------|
|---------------------|------------------------|----------|--------------|------------|
| 0 - 999 | | Yes | No | Unused |
| 1000 | `CLOSE_NORMAL` | No | No | Successful operation / regular socket shutdown |
| 1001 | `CLOSE_GOING_AWAY` | No | No | Client is leaving |
......@@ -25,4 +25,5 @@
| 4000 | | No | Yes | Expected object was not received |
| 4001 | | No | Yes | Failed to get timestamp data |
| 4002 | | No | Yes | Please wipe your data and resync |
| 4003 - 4999 | | No | Yes | Available for applications |
\ No newline at end of file
| 4003 | | No | Yes | Unexpected Initial Point datetime format received |
| 4004 - 4999 | | No | Yes | Available for applications |
\ No newline at end of file
from bson import timestamp
from aiohttp import WSMsgType
import ujson
import iso8601
from mongodb_mirror.errors import MirrorUnexpectedResponse, WSMsgTypeClosedException, UnexpectedWSMsgTypeException
from mongodb_mirror.errors import (MirrorUnexpectedResponse, WSMsgTypeClosedException, UnexpectedWSMsgTypeException,
IncorrectInitPoint)
from prozorro_sale.tools import logger
......@@ -95,6 +97,19 @@ class SocketMirrorClientSimpleProtocol(BaseSocketMirrorClient):
response_data = await self.receive_json()
if response_data['type'] != 'init-point-request':
raise MirrorUnexpectedResponse('Initial point', response_data)
if init_point := response_data['data']:
try:
iso8601.parse_date(init_point)
except iso8601.ParseError:
LOG.info(f'Invalid datetime format for Initial point : {init_point}. Should be iso8601')
error_message = {
"init_point": f"Invalid datetime format for Initial point: {init_point}. Should be iso8601."
}
await self._send_error(error_message, error_code=4003)
LOG.info('Client disconnect cause of incorrect init_point date format')
raise IncorrectInitPoint(init_point)
return response_data['data']
async def upsert(self, ts, data):
......@@ -122,18 +137,22 @@ class SocketMirrorClientSimpleProtocol(BaseSocketMirrorClient):
Not available for the simple protocol
"""
async def handle_error(self, ts, object_id, error_message, error_code=4000):
await self.ws.send_json({
async def _send_error(self, error_message, error_code=4000, ts=None, **extra_data):
data = {
"type": "error",
"data": {
"_id": str(object_id),
"error": {
"code": error_code,
"message": error_message
}
},
'ts': ts
}, dumps=ujson.dumps)
}
data['data'].update(extra_data)
await self.ws.send_json(data, dumps=ujson.dumps)
async def handle_error(self, ts, object_id, error_message, error_code=4000):
await self._send_error(error_message=error_message, ts=ts, _id=str(object_id))
class SocketMirrorClientFullProtocol(SocketMirrorClientSimpleProtocol):
......
......@@ -32,6 +32,13 @@ class IncorrectTimestamp(MirrorException):
f' Please wipe your data and resync')
class IncorrectInitPoint(MirrorException):
def __init__(self, init_point):
super().__init__(
f'Invalid datetime format for Initial point: {init_point}. Should be iso8601.'
)
class CriticalError(MirrorException):
def __init__(self, msg):
super().__init__(f'{msg}')
......@@ -19,7 +19,8 @@ from prozorro_sale.tools import logger
from prozorro_sale.tools.middlewares import request_id_middleware
from prozorro_sale.tools.environment import booleans
from mongodb_mirror.utils import MongoOperation
from mongodb_mirror.errors import ClientTimestampException, IncorrectTimestamp, CriticalError, MirrorClosed
from mongodb_mirror.errors import (ClientTimestampException, IncorrectTimestamp, CriticalError,
MirrorClosed)
from diskcache import Cache
import prometheus_client
......
from asyncio import CancelledError
from aiohttp import WSCloseCode
from mongodb_mirror.errors import (MirrorUnexpectedResponse, ClientTimestampException, WSMsgTypeClosedException,
UnexpectedWSMsgTypeException, IncorrectTimestamp, CriticalError, MirrorClosed)
UnexpectedWSMsgTypeException, IncorrectTimestamp, IncorrectInitPoint, CriticalError,
MirrorClosed)
def namespace_to_db_collection(namespace):
......@@ -75,6 +76,7 @@ WEBSOCKET_CLOSE_CODE_DICT = {
MirrorUnexpectedResponse: (4000, b'Expected object was not received'),
ClientTimestampException: (4001, b'Failed to get timestamp data'),
IncorrectTimestamp: (4002, b'Please wipe your data and resync'),
IncorrectInitPoint: (4003, b'Unexpected Initial Point datetime format received'),
WSMsgTypeClosedException: (1001, b'Client is leaving'),
UnexpectedWSMsgTypeException: (WSCloseCode.UNSUPPORTED_DATA, b'Endpoint receiv only MsgType TEXT'),
CriticalError: (WSCloseCode.INTERNAL_ERROR, b'Internal server error while operating'),
......
......@@ -10,7 +10,8 @@ from mongodb_mirror.client import (
SocketMirrorClientSimpleProtocol,
SocketMirrorClientFullProtocol
)
from mongodb_mirror.errors import WSMsgTypeClosedException, UnexpectedWSMsgTypeException, MirrorUnexpectedResponse
from mongodb_mirror.errors import (WSMsgTypeClosedException, UnexpectedWSMsgTypeException, MirrorUnexpectedResponse,
IncorrectInitPoint)
from unittest.mock import Mock, AsyncMock
......@@ -105,6 +106,27 @@ class TestSocketMirrorClientSimpleProtocol:
'data': ''
}, dumps=ujson.dumps)
async def test_get_sync_init_point_incorrect_dt(self):
init_point_value = "wrong_date_format"
test_ws = Mock()
test_ws.send_json = AsyncMock()
test_client = SocketMirrorClientSimpleProtocol(ws=test_ws, namespace='test')
test_client.receive_json = AsyncMock(return_value={
'type': 'init-point-request',
'data': init_point_value})
test_client._send_error = AsyncMock()
message = f"Invalid datetime format for Initial point: {init_point_value}. Should be iso8601."
error_message = {
"init_point": message
}
with pytest.raises(IncorrectInitPoint, match=f'{message}'):
await test_client.get_sync_init_point()
test_client._send_error.assert_called_once_with(
error_message, error_code=4003
)
async def test_upsert(self):
test_ws = Mock()
test_ws.send_json = AsyncMock()
......
Supports Markdown
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