summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomek Dubrownik <t.dubrownik@gmail.com>2012-01-06 22:38:31 +0100
committerTomek Dubrownik <t.dubrownik@gmail.com>2012-01-06 22:38:31 +0100
commitdacfb779b08b2093bc9a3ebcd85b60685b117fab (patch)
tree786ec69f7f19ee7677a72ba2113fb48b6f036bbe
parent2bf714766cc0ae17b526d0de909f83f1b4c9031b (diff)
downloaddoorman-dacfb779b08b2093bc9a3ebcd85b60685b117fab.tar.gz
doorman-dacfb779b08b2093bc9a3ebcd85b60685b117fab.tar.bz2
doorman-dacfb779b08b2093bc9a3ebcd85b60685b117fab.tar.xz
doorman-dacfb779b08b2093bc9a3ebcd85b60685b117fab.zip
set of changes adding flags to _add, _revoke_{card,user}
try them with -h/--help
-rwxr-xr-xadmin/doorman_add55
-rwxr-xr-xadmin/doorman_revoke_card41
-rwxr-xr-xadmin/doorman_revoke_user39
-rw-r--r--admin/lib/csvstore.py37
-rw-r--r--admin/lib/jsonstore.py25
-rw-r--r--admin/lib/storage.py48
-rw-r--r--admin/lib/storage/storage_encapsulation.py12
-rw-r--r--admin/lib/storage_encapsulation.py136
8 files changed, 100 insertions, 293 deletions
diff --git a/admin/doorman_add b/admin/doorman_add
index 248d0e8..7f9ec82 100755
--- a/admin/doorman_add
+++ b/admin/doorman_add
@@ -8,21 +8,42 @@ from lib.actions import *
from lib.storage import add_user
from lib.password import get_token, get_pin
+import options
if __name__ == '__main__':
- url = argv[2] if len(argv) > 2 else None
- uname = argv[1]
- token = get_token()
- proto = Proto(url)
- print 'Please swipe token'
- frame = scan(token=token, proto=proto)
- assert(frame.command.upper() == 'S')
- if frame.uid:
- print >> stderr, 'E: Token already in use (user %d)' % frame.uid
- exit(1)
- status = add(token, frame.hash, proto=proto)
- if status.command.upper() == 'C':
- add_user(uname, frame.hash, status.uid)
- print 'User %s added successfully (uid=%d)' % (uname, status.uid)
- else:
- print >> stderr, 'Unknown error:', str(status)
- exit(1)
+ parser = argparse.ArgumentParser(
+ description='Add a card')
+ parser.add_argument('name',
+ help='Card owner\'s username')
+ parser.add_argument('url',
+ help='Serial connection to use',
+ default=options.url,
+ nargs='?')
+ parser.add_argument('-l', '--local', action='store_true',
+ help='If specified, only update local base',)
+ parser.add_argument('-c', '--card', help='Card+PIN hash (will not scan)')
+ parser.add_argument('-u', '--uid', help='Short unique ID of the card', type=int)
+ args = parser.parse_args()
+ uid = args.uid
+ card = args.card
+ uname = args.name
+ if args.local and not (args.card and args.uid):
+ print 'Local update requires a card and uid to be specified!'
+ exit(2)
+ if not args.local:
+ token = get_token()
+ proto = Proto(args.url)
+ if not args.card:
+ print 'Please swipe token'
+ frame = scan(token=token, proto=proto)
+ assert(frame.command.upper() == 'S')
+ card = frame.hash
+ uid = frame.uid
+ if frame.uid:
+ print >> stderr, 'E: Token already in use (user %d)' % frame.uid
+ exit(1)
+ status = add(token, frame.hash, proto=proto)
+ if status.command.upper() != 'C':
+ print >> stderr, 'Unknown error:', str(status)
+ exit(1)
+ add_user(uname, card, uid)
+ print 'User %s added successfully (uid=%d)' % (uname, uid)
diff --git a/admin/doorman_revoke_card b/admin/doorman_revoke_card
index cce1db1..7cecfc8 100755
--- a/admin/doorman_revoke_card
+++ b/admin/doorman_revoke_card
@@ -9,16 +9,31 @@ from lib.storage import del_card
from lib.password import get_token
if __name__ == '__main__':
- url = argv[1] if len(argv) > 1 else None
- token = get_token()
- proto = Proto(url)
- print 'Please swipe token'
- card = scan(token, proto=proto)
- assert(card.command == 'S')
- status = revoke_mid(token, card.mid, proto=proto)
- if status.command == 'K':
- (uid, name) = del_card(card.mid)
- print 'Card %x (user %s, uid %d) revoked' % (card.mid, name, card.uid)
- else:
- print >> stderr, 'Unknown error:', str(status)
- exit(1)
+ parser = argparse.ArgumentParser(
+ description='Revoke a single card')
+ parser.add_argument('url',
+ help='Serial connection to use',
+ default=options.url,
+ nargs='?')
+ parser.add_argument('-l', '--local', action='store_true',
+ help='If specified, only update local base',)
+ parser.add_argument('-c', '--card', help='Card+PIN hash (will not scan), only required with -l')
+ args = parser.parse_args()
+ if args.local and not args.card:
+ print 'Local update requires a card to be specified!'
+ exit(2)
+ card = args.card
+ if not args.local:
+ token = get_token()
+ proto = Proto(args.url)
+ if not args.card:
+ print 'Please swipe token'
+ frame = scan(token, proto=proto)
+ assert(frame.command == 'S')
+ card = frame.hash
+ status = revoke_mid(token, card, proto=proto)
+ if status.command != 'K':
+ print >> stderr, 'Unknown error:', str(status)
+ exit(1)
+ (uid, name) = del_card(card)
+ print 'Card %x (user %s, uid %d) revoked' % (card, name, uid)
diff --git a/admin/doorman_revoke_user b/admin/doorman_revoke_user
index af87735..11e754c 100755
--- a/admin/doorman_revoke_user
+++ b/admin/doorman_revoke_user
@@ -1,6 +1,7 @@
#!/usr/bin/env python
import argparse
+import options
from sys import stderr, argv
from lib.actions import *
@@ -9,18 +10,34 @@ from lib.storage import cards_for_user, del_card
from lib.password import get_token
if __name__ == '__main__':
- url = argv[2] if len(argv) > 2 else None
- token = get_token()
- proto = Proto(url)
- user = argv[1]
+ parser = argparse.ArgumentParser(
+ description='Revoke all cards for a single user')
+ parser.add_argument('name',
+ help='User whose cards will be revoked')
+ parser.add_argument('url',
+ help='Serial connection to use',
+ default=options.url,
+ nargs='?')
+ parser.add_argument('-l', '--local', action='store_true',
+ help='If specified, only update local base',)
+ args = parser.parse_args()
+ user = args.name
cards = cards_for_user(user)
- for h in cards:
- print 'Revoking card %s' % h
- status = revoke_hash(token, h, proto=proto)
- if status.command == 'K':
+ if args.local:
+ for h in cards:
del_card(h)
print 'Card %s revoked' % h
- else:
- print >> stderr, 'Unknown error:', status
- exit(1)
+ else:
+ token = get_token()
+ proto = Proto(url)
+ user = argv[1]
+ for h in cards:
+ print 'Revoking card %s' % h
+ status = revoke_hash(token, h, proto=proto)
+ if status.command == 'K':
+ del_card(h)
+ print 'Card %s revoked' % h
+ else:
+ print >> stderr, 'Unknown error:', status
+ exit(1)
print 'User %s\'s cards revoked' % user
diff --git a/admin/lib/csvstore.py b/admin/lib/csvstore.py
deleted file mode 100644
index 8bb8965..0000000
--- a/admin/lib/csvstore.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from sys import stderr
-from UserDict import IterableUserDict
-from StringIO import StringIO
-
-import csv
-
-class Storage(IterableUserDict):
- def __init__(self, encapsulation):
- self.encapsulation = encapsulation
- self.encapsulation.begin_transaction()
- try:
- stored = {x[0]: [x[1], x[2]]
- for x in csv.reader(StringIO(self.encapsulation.data))}
- except IOError as e:
- print >>stderr, e
- stored = {}
- IterableUserDict.__init__(self, stored)
- def sync(self):
- f = StringIO()
- csv.writer(f).writerows(
- [c, u, name] for c, (u, name) in self.data.iteritems())
-
- self.encapsulation.data = f.getvalue()
- self.encapsulation.end_transaction()
- f.close()
-
- self.encapsulation.begin_transaction()
- def __del__(self):
- #TODO: fix this shit
- #self.sync()
- pass
- def __setitem__(self, k, v):
- IterableUserDict.__setitem__(self, k, v)
- self.sync()
- def __delitem__(self, k):
- IterableUserDict.__delitem__(self, k)
- self.sync()
diff --git a/admin/lib/jsonstore.py b/admin/lib/jsonstore.py
deleted file mode 100644
index 48dcc9e..0000000
--- a/admin/lib/jsonstore.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import json
-
-from UserDict import IterableUserDict
-
-class Storage(IterableUserDict):
- def __init__(self, encapsulation):
- self.encapsulation = encapsulation
- self.encapsulation.begin_transaction()
- try:
- stored = json.loads(self.encapsulation.data)
- except IOError:
- stored = {}
- IterableUserDict.__init__(self, stored)
- def __setitem__(self, k, v):
- IterableUserDict.__setitem__(self, k, v)
- self.sync()
- def __delitem__(self, k):
- IterableUserDict.__delitem__(self, k)
- self.sync()
- def __del__(self):
- self.sync()
- def sync(self):
- self.encapsulation.data = json.dumps(self.data, indent=4)
- self.encapsulation.end_transaction()
- self.encapsulation.begin_transaction()
diff --git a/admin/lib/storage.py b/admin/lib/storage.py
deleted file mode 100644
index d68c868..0000000
--- a/admin/lib/storage.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import shelve
-
-import csvstore
-import jsonstore
-import options
-import storage_encapsulation
-
-if options.storage_encrypt == True:
- encapsulation_class = storage_encapsulation.DESFileEncapsulation
-else:
- encapsulation_class = storage_encapsulation.RawFileEncapsulation
-
-if options.storage == 'shelve':
- if options.storage_encrypt == True:
- raise NotImplementedError("Who the fuck uses Shelve anyway.")
- storage = shelve.open(options.shelf)
-if options.storage == 'json':
- encapsulation = encapsulation_class(options.json)
- storage = jsonstore.Storage(encapsulation)
-if options.storage == 'csv':
- encapsulation = encapsulation_class(options.csv)
- storage = csvstore.Storage(encapsulation)
-
-nobody = (None, '-unknown-')
-
-to_hex = lambda v: '%x' % v
-from_hex = lambda v: int(v, 16)
-dehex = lambda s: int(s.translate(None, 'xXlL'), 16)
-
-get_card = lambda h: storage.get(h, nobody)
-cards_for_user = lambda name: map(lambda (k,v): from_hex(k),
- filter(lambda (k,(u,n)): n == name, storage.iteritems()))
-
-def add_user(username, hash, uid):
- storage[hash] = (uid, username)
-
-def del_card(hash):
- return storage.pop(hash, nobody)
-
-def del_filter(f):
- cards = map(lambda (k,v): k, filter(f, storage.iteritems()))
- r = []
- for c in cards:
- r.append(storage.pop(c, nobody))
- return r
-
-del_uid = lambda uid: del_filter(lambda (k, (u,n)): u == uid)
-del_username = lambda name: del_filter(lambda (k, (u,n)): n == name)
diff --git a/admin/lib/storage/storage_encapsulation.py b/admin/lib/storage/storage_encapsulation.py
index 6c37692..9456be3 100644
--- a/admin/lib/storage/storage_encapsulation.py
+++ b/admin/lib/storage/storage_encapsulation.py
@@ -7,7 +7,7 @@ import hashlib
import os
import tempfile
-import lib.password
+import lib.password as password
class RawFileEncapsulation(object):
"""
@@ -53,9 +53,9 @@ class RawFileEncapsulation(object):
Verifies everything went well and commits changes to the file.
"""
- original = open(self.original_filename, "rb")
- verification_data = self._decode_data(original.read())
- verification_checksum = hashlib.sha1(verification_data).hexdigest()
+ with open(self.original_filename, "rb") as original:
+ verification_data = self._decode_data(original.read())
+ verification_checksum = hashlib.sha1(verification_data).hexdigest()
if verification_checksum != self.original_checksum:
#TODO: Implement separate exception
@@ -72,8 +72,8 @@ class RawFileEncapsulation(object):
# opened by another program here and it can be modified!
# Oh well.
- original = open(self.original_filename, "wb")
- original.write(self._encode_data(self.data))
+ with open(self.original_filename, "wb") as original:
+ original.write(self._encode_data(self.data))
# Remove the backup.
os.remove(backup_filename)
diff --git a/admin/lib/storage_encapsulation.py b/admin/lib/storage_encapsulation.py
deleted file mode 100644
index a2ce582..0000000
--- a/admin/lib/storage_encapsulation.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# because admin.lib.password uses admin.options -_-
-if __name__ == "__main__":
- import sys
- sys.path.append("d:\\Development\\Projects\\doorman\\admin")
-
-import hashlib
-import os
-import tempfile
-
-import password
-
-class RawFileEncapsulation(object):
- """
- Encapsulates data in a file. With style!
-
- The data is available in .data.
- """
-
- def __init__(self, filename):
- self.original_filename = filename
- self.original_checksum = None
- self.storage = None
-
- def _decode_data(self, data):
- """
- Override me.
- """
- return data
-
- def _encode_data(self, data):
- """
- Override me.
- """
- return data
-
- def _backup_file_path(self, original_path):
- """
- Override me if you care.
- """
- return original_path + "_OHSHITSOMETHINGWENTWRONG"
-
- def begin_transaction(self):
- """
- Creates a temporary file that we'll use before writing all.
- """
-
- with open(self.original_filename, "rb") as original:
- self.data = self._decode_data(original.read())
- self.original_checksum = hashlib.sha1(self.data).hexdigest()
-
- def end_transaction(self):
- """
- Verifies everything went well and commits changes to the file.
- """
-
- original = open(self.original_filename, "rb")
- verification_data = self._decode_data(original.read())
- verification_checksum = hashlib.sha1(verification_data).hexdigest()
-
- if verification_checksum != self.original_checksum:
- #TODO: Implement separate exception
- raise Exception("File changed since we last opened it!")
-
- # Let's make a backup of the old original... Because we're paranoid.
- # We're writing the encapsulated versiuon here so that it can be a
- # drop-in replacement.
- backup_filename = self._backup_file_path(self.original_filename)
- with open(backup_filename, "wb") as backup:
- backup.write(verification_data)
-
- # BIG TODO: Fix the race condition that occurs here: the file can be
- # opened by another program here and it can be modified!
- # Oh well.
-
- original = open(self.original_filename, "wb")
- original.write(self._encode_data(self.data))
-
- # Remove the backup.
- os.remove(backup_filename)
-
-class DESFileEncapsulation(RawFileEncapsulation):
- MAGIC = "it's a kind of magic!"
- def __init__(self, filename, magic_check=True):
- try:
- import Crypto
- except:
- raise Exception("PyCrypto not installed!")
-
- self.des_key = password.get_des_storage_key(filename)
- self.magic_check = magic_check
- super(DESFileEncapsulation, self).__init__(filename)
-
- def _decode_data(self, data):
- if data == "":
- print "Input file empty. Assuming actually empty file."
- return ""
-
- from Crypto.Cipher import DES
- des = DES.new(self.des_key, DES.MODE_CBC)
- data_padded = des.decrypt(data)
-
- padding_length = ord(data_padded[-1])
- data_unpadded = data_padded[:-padding_length]
-
- if self.magic_check and not data_unpadded.startswith(self.MAGIC):
- raise Exception("Bad magic! Did you mistype a key?")
-
- return data_unpadded[len(self.MAGIC):]
-
- def _encode_data(self, data):
- from Crypto.Cipher import DES
- des = DES.new(self.des_key, DES.MODE_CBC)
-
- if self.magic_check:
- data = self.MAGIC + data
- padding_length = 8 - len(data) % 8
- data_padded = data + chr(padding_length) * padding_length
-
- return des.encrypt(data_padded)
-
-if __name__ == "__main__":
- r = DESFileEncapsulation("d:/dupa.txt")
- r.begin_transaction()
-
- try:
- n = int(r.data)
- except:
- n = 0
-
- print "ass! %i" % n
- r.data = str(n + 1)
-
- print "try to modify the assfile, see it fail!"
- raw_input()
-
- r.end_transaction() \ No newline at end of file