Parse log sent be lockout, normalize cards
This commit is contained in:
parent
8317a9524a
commit
571cdd37f0
|
@ -31,8 +31,8 @@ class Profile(models.Model):
|
||||||
return self.user.username
|
return self.user.username
|
||||||
|
|
||||||
class Card(models.Model):
|
class Card(models.Model):
|
||||||
profile = models.OneToOneField(Profile, on_delete=models.CASCADE, editable=False)
|
profile = models.ForeignKey(Profile, related_name='cards', on_delete=models.CASCADE)
|
||||||
number = models.CharField(max_length=512) # TODO: normalize
|
number = models.CharField(max_length=10)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.number
|
return self.number
|
||||||
|
|
|
@ -32,11 +32,7 @@ class ToolDataSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
|
||||||
class ProfileSerializer(serializers.HyperlinkedModelSerializer):
|
class ProfileSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
user = serializers.StringRelatedField()
|
user = serializers.StringRelatedField()
|
||||||
card = serializers.SlugRelatedField(
|
cards = serializers.StringRelatedField(many=True, read_only=True)
|
||||||
allow_null=True,
|
|
||||||
slug_field='number',
|
|
||||||
queryset=models.Card.objects.all()
|
|
||||||
)
|
|
||||||
authorized_tools = serializers.SlugRelatedField(
|
authorized_tools = serializers.SlugRelatedField(
|
||||||
many=True,
|
many=True,
|
||||||
slug_field='slug',
|
slug_field='slug',
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import requests
|
import base64
|
||||||
import json
|
import json
|
||||||
|
import requests
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
@ -11,6 +14,9 @@ from rest_framework.response import Response
|
||||||
from . import models, serializers
|
from . import models, serializers
|
||||||
from authserver.settings import PROTOSPACE_LOGIN_PAGE
|
from authserver.settings import PROTOSPACE_LOGIN_PAGE
|
||||||
|
|
||||||
|
LOG_DIRECTORY = '/var/log/pslockout'
|
||||||
|
VALID_TIME = 1000000000
|
||||||
|
|
||||||
class IsLockoutAdmin(permissions.BasePermission):
|
class IsLockoutAdmin(permissions.BasePermission):
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
try:
|
try:
|
||||||
|
@ -65,7 +71,9 @@ def login(request):
|
||||||
if res.status_code == requests.codes.ok:
|
if res.status_code == requests.codes.ok:
|
||||||
return Response({'error': 'Invalid Credentials'}, status=status.HTTP_404_NOT_FOUND)
|
return Response({'error': 'Invalid Credentials'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
user, created = User.objects.get_or_create(username=username)
|
lockout_username = username.replace('.', '')
|
||||||
|
|
||||||
|
user, created = User.objects.get_or_create(username=lockout_username)
|
||||||
user.set_password(password) # not validated
|
user.set_password(password) # not validated
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
@ -95,13 +103,78 @@ def update_cards(request):
|
||||||
|
|
||||||
for username, card_numbers in data.items():
|
for username, card_numbers in data.items():
|
||||||
try:
|
try:
|
||||||
profile = models.Profile.objects.get(user__username=username)
|
lockout_username = username.replace('.', '')
|
||||||
card, _ = models.Card.objects.update_or_create(
|
profile = models.Profile.objects.get(user__username=lockout_username)
|
||||||
profile=profile,
|
except models.Profile.DoesNotExist:
|
||||||
defaults={'number': card_numbers}
|
|
||||||
)
|
|
||||||
if card: updated_count += 1
|
|
||||||
except:
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
for card_number in card_numbers.split(','):
|
||||||
|
card, _ = models.Card.objects.get_or_create(
|
||||||
|
profile=profile,
|
||||||
|
number=card_number
|
||||||
|
)
|
||||||
|
if card: updated_count += 1
|
||||||
|
|
||||||
return Response({'updated': updated_count}, status=status.HTTP_200_OK)
|
return Response({'updated': updated_count}, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
EVENTS = [
|
||||||
|
'LOG_BOOT_UP - Booted up =============================================',
|
||||||
|
'LOG_INIT_COMPLETE - Initialization completed',
|
||||||
|
'LOG_WIFI_CONNECTED - Wifi connected',
|
||||||
|
'LOG_WIFI_DISCONNECTED - Wifi disconnected',
|
||||||
|
'LOG_COMM_LOCK_ARM - Received arm request over web',
|
||||||
|
'LOG_COMM_LOCK_DISARM - Received disarm request over web',
|
||||||
|
'LOG_COMM_LOCK_FAIL - Lock status communication failed, code: ',
|
||||||
|
'LOG_COMM_CARD_FAIL - Card list communication failed, code: ',
|
||||||
|
'LOG_COMM_INFO_FAIL - Info log communication failed, code: ',
|
||||||
|
'LOG_LOCK_OFF - Lock turned off',
|
||||||
|
'LOG_LOCK_ARMED - Lock armed',
|
||||||
|
'LOG_LOCK_TIMEOUT - Lock arming timed out',
|
||||||
|
'LOG_LOCK_ON - Lock turned on',
|
||||||
|
'LOG_LOCK_DISARMED - Lock disarmed',
|
||||||
|
'LOG_LOCK_ERROR - Button held while arming lock',
|
||||||
|
'LOG_CARD_GOOD_READ - Successful read from card: ',
|
||||||
|
'LOG_CARD_ACCEPTED - Accepted card: ',
|
||||||
|
'LOG_CARD_DENIED - Denied card: ',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@api_view(["POST"])
|
||||||
|
def infolog(request, mac):
|
||||||
|
entries_processed = 0
|
||||||
|
oldest_valid_log_time = time.time()
|
||||||
|
|
||||||
|
encoded_log = request.data.get('log')
|
||||||
|
if encoded_log:
|
||||||
|
decoded_log = base64.b64decode(encoded_log)
|
||||||
|
unpacked_log = list(struct.iter_unpack('<IB10s', decoded_log))
|
||||||
|
|
||||||
|
for entry in unpacked_log:
|
||||||
|
if entry[0] < oldest_valid_log_time and entry[0] > VALID_TIME:
|
||||||
|
oldest_valid_log_time = entry[0]
|
||||||
|
|
||||||
|
with open(LOG_DIRECTORY + '/devices/' + mac + '.log', 'a') as log_file:
|
||||||
|
for entry in unpacked_log:
|
||||||
|
# if time is obviously wrong, just use oldest valid log time or now
|
||||||
|
entry_time = entry[0] if entry[0] > VALID_TIME else oldest_valid_log_time
|
||||||
|
entry_time_string = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(entry_time))
|
||||||
|
|
||||||
|
entry_event = EVENTS[entry[1]]
|
||||||
|
entry_data = entry[2].decode('utf-8').strip('\0')
|
||||||
|
|
||||||
|
if entry_data:
|
||||||
|
user = models.User.objects.filter(profile__cards__number=entry_data)
|
||||||
|
if user.count():
|
||||||
|
entry_data += ' (' + str(user.first()) + ')'
|
||||||
|
|
||||||
|
entry_string = '{} - {} - {}{}'.format(entry_time_string, mac, entry_event, entry_data)
|
||||||
|
|
||||||
|
entries_processed += 1
|
||||||
|
log_file.write(entry_string + '\n')
|
||||||
|
|
||||||
|
response_object = {
|
||||||
|
'unixTime': int(time.time()),
|
||||||
|
'processed': entries_processed,
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response(response_object, status=status.HTTP_200_OK)
|
||||||
|
|
|
@ -35,7 +35,8 @@ urlpatterns = [
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
url(r'^login/', views.login),
|
url(r'^login/', views.login),
|
||||||
url(r'^cards/(?P<mac>.*)/', views.cards),
|
url(r'^cards/(?P<mac>.*)/', views.cards),
|
||||||
url(r'^update-cards/', views.update_cards)
|
url(r'^update-cards/', views.update_cards),
|
||||||
|
url(r'^infolog/(?P<mac>.*)/', views.infolog),
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG is True:
|
if settings.DEBUG is True:
|
||||||
|
|
51
authserver/parselog_example.py
Normal file
51
authserver/parselog_example.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import base64
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
|
|
||||||
|
EVENTS = [
|
||||||
|
'LOG_BOOT_UP - Booted up',
|
||||||
|
'LOG_INIT_COMPLETE - Initialization completed',
|
||||||
|
'LOG_WIFI_CONNECTED - Wifi connected',
|
||||||
|
'LOG_WIFI_DISCONNECTED - Wifi disconnected',
|
||||||
|
'LOG_COMM_LOCK_FAIL - Lock status communication failed, code: ',
|
||||||
|
'LOG_COMM_CARD_FAIL - Card list communication failed, code: ',
|
||||||
|
'LOG_COMM_INFO_FAIL - Info log communication failed, code: ',
|
||||||
|
'LOG_LOCK_OFF - Lock turned off',
|
||||||
|
'LOG_LOCK_ARMED - Lock armed',
|
||||||
|
'LOG_LOCK_TIMEOUT - Lock armed timed out',
|
||||||
|
'LOG_LOCK_ON - Lock turned on',
|
||||||
|
'LOG_LOCK_CANCEL - Lock armed cancelled',
|
||||||
|
'LOG_LOCK_ERROR - Lock armed button error',
|
||||||
|
'LOG_CARD_GOOD_READ - Successful read from card: ',
|
||||||
|
'LOG_CARD_ACCEPTED - Accepted card: ',
|
||||||
|
'LOG_CARD_DENIED - Denied card: ',
|
||||||
|
]
|
||||||
|
|
||||||
|
encoded = "AAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAABgAAAAIAAAAAAAAAAAAABwAAAAQ1MDMAAAAAAAAA0whEXA0wNzAwQjU2MUMx0whEXA8wNzAwQjU2MUMx1AhEXA0wNzAwQjU2MUMx1AhEXA8wNzAwQjU2MUMx6whEXA0wNzAwQjU2MUMx6whEXA8wNzAwQjU2MUMx7AhEXA0wNzAwQjU2MUMx7AhEXA8wNzAwQjU2MUMx7ghEXA0wNzAwQjU2MUMx7ghEXA8wNzAwQjU2MUMx7whEXA0wNzAwQjU2MUMx7whEXA8wNzAwQjU2MUMx8AhEXA0wNzAwQjU2MUMx8AhEXA8wNzAwQjU2MUMx8QhEXA0wNzAwQjU2MUMx8QhEXA8wNzAwQjU2MUMx8QhEXA0wNzAwQjU2MUMx8QhEXA8wNzAwQjU2MUMx8ghEXA0wNzAwQjU2MUMx8ghEXA8wNzAwQjU2MUMx8whEXA0wNzAwQjU2MUMx8whEXA8wNzAwQjU2MUMx8whEXA0wNzAwQjU2MUMx8whEXA8wNzAwQjU2MUMx9AhEXA0wNzAwQjU2MUMx9AhEXA8wNzAwQjU2MUMx9QhEXA0wNzAwQjU2MUMx9QhEXA8wNzAwQjU2MUMx9QhEXA0wNzAwQjU2MUMx9QhEXA8wNzAwQjU2MUMx9ghEXA0wNzAwQjU2MUMx9ghEXA8wNzAwQjU2MUMx9whEXA0wNzAwQjU2MUMx9whEXA8wNzAwQjU2MUMx9whEXA0wNzAwQjU2MUMx9whEXA8wNzAwQjU2MUMx+AhEXA0wNzAwQjU2MUMx+AhEXA8wNzAwQjU2MUMx+AhEXA0wNzAwQjU2MUMx+AhEXA8wNzAwQjU2MUMx+QhEXA0wNzAwQjU2MUMx+QhEXA8wNzAwQjU2MUMx+whEXA0wNzAwQjU2MUMx+whEXA8wNzAwQjU2MUMx/AhEXA0wNzAwQjU2MUMx/AhEXA8wNzAwQjU2MUMx/QhEXA0wNzAwQjU2MUMx/QhEXA8wNzAwQjU2MUMx/ghEXA0wNzAwQjU2MUMx/ghEXA8wNzAwQjU2MUMx/whEXA0wNzAwQjU2MUMx/whEXA8wNzAwQjU2MUMxAAlEXA0wNzAwQjU2MUMxAAlEXA8wNzAwQjU2MUMxAQlEXA0wNzAwQjU2MUMxAQlEXA8wNzAwQjU2MUMxAglEXA0wNzAwQjU2MUMxAglEXA8wNzAwQjU2MUMxAwlEXA0wNzAwQjU2MUMxAwlEXA8wNzAwQjU2MUMxAwlEXA0wNzAwQjU2MUMxAwlEXA8wNzAwQjU2MUMxBQlEXA0wNzAwQjU2MUMxBQlEXA8wNzAwQjU2MUMxBglEXAY1MDAAAAAAAAAABglEXA0wNzAwQjU2MUMxBglEXA8wNzAwQjU2MUMxBwlEXA0wNzAwQjU2MUMxBwlEXA8wNzAwQjU2MUMxBwlEXA0wNzAwQjU2MUMxBwlEXA8wNzAwQjU2MUMxCAlEXA0wNzAwQjU2MUMxCAlEXA8wNzAwQjU2MUMxCQlEXA0wNzAwQjU2MUMxCQlEXA8wNzAwQjU2MUMxCQlEXA0wNzAwQjU2MUMxCQlEXA8wNzAwQjU2MUMxCQlEXA0wNzAwQjU2MUMxCQlEXA8wNzAwQjU2MUMxCglEXA0wNzAwQjU2MUMxCglEXA8wNzAwQjU2MUMxCwlEXA0wNzAwQjU2MUMxCwlEXA8wNzAwQjU2MUMxDAlEXA0wNzAwQjU2MUMxDAlEXA8wNzAwQjU2MUMxDAlEXA0wNzAwQjU2MUMx"
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
decoded = base64.b64decode(encoded)
|
||||||
|
|
||||||
|
unpacked = list(struct.iter_unpack('<IB10s', decoded))
|
||||||
|
|
||||||
|
entries_processed = 0
|
||||||
|
|
||||||
|
for entry in unpacked:
|
||||||
|
# if time is obviously wrong, just use the time right now
|
||||||
|
entry_time = entry[0] if entry[0] > 1000000 else int(time.time())
|
||||||
|
entry_time_string = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(entry_time))
|
||||||
|
entry_event = EVENTS[entry[1]]
|
||||||
|
entry_data = entry[2].decode('ascii')
|
||||||
|
|
||||||
|
entry_string = entry_time_string + ' - ' + entry_event + entry_data
|
||||||
|
|
||||||
|
print(entry_string)
|
||||||
|
print(len(unpacked))
|
||||||
|
break
|
||||||
|
|
||||||
|
except:
|
||||||
|
print('bad parse')
|
||||||
|
encoded = encoded[:-1]
|
Loading…
Reference in New Issue
Block a user