diff --git a/minigrid/device_interface.py b/minigrid/device_interface.py index d938fa8..7c46c6e 100644 --- a/minigrid/device_interface.py +++ b/minigrid/device_interface.py @@ -21,6 +21,42 @@ def _wrap_binary(binary): return b'qS' + binary.hex().encode('ascii') + b'EL' +def erase_card(session, cache): + """Erase card.""" + sector_1 = b''.join(( + bytes(45), + )) + sector_2 = b''.join(( + bytes(32), + )) + naive_payload = sector_1 + sector_2 + actual_payload = b''.join(( + naive_payload[:15], + (sum(naive_payload[:15]) & 0xFF).to_bytes(1, 'big'), + naive_payload[15:30], + (sum(naive_payload[15:30]) & 0xFF).to_bytes(1, 'big'), + naive_payload[30:45], + (sum(naive_payload[30:45]) & 0xFF).to_bytes(1, 'big'), + naive_payload[45:60], + (sum(naive_payload[45:60]) & 0xFF).to_bytes(1, 'big'), + naive_payload[60:75], + (sum(naive_payload[60:75]) & 0xFF).to_bytes(1, 'big'), + naive_payload[75:77], + bytes(13), + (sum(naive_payload[75:77]) & 0xFF).to_bytes(1, 'big'), + )) + cache.set('device_info', _wrap_binary(actual_payload), 30) + write_result = OrderedDict() + write_result['card_type'] = 'Blank Card' + write_result['future_time'] = str(int(time.time())+30) + cache.set('write_info', json_encode(write_result), 30) + notify = OrderedDict() + notify['notification'] = 'Erasing Card...' + notify['type'] = 'alert-warning' + cache.set('notification', json_encode(notify), 30) + cache.delete('received_info') + + def write_vendor_card(session, cache, key, minigrid_id, payment_id, vendor): """Write information to a vendor ID card.""" card_produce_time = int(time.time()) diff --git a/minigrid/handlers.py b/minigrid/handlers.py index 15f4db1..34d6a7f 100644 --- a/minigrid/handlers.py +++ b/minigrid/handlers.py @@ -1,4 +1,5 @@ """Handlers for the URL endpoints.""" +import time from binascii import unhexlify from collections import OrderedDict from datetime import datetime, timedelta @@ -26,7 +27,7 @@ import tornado.ioloop from minigrid.device_interface import ( - write_maintenance_card_card, + write_maintenance_card_card, erase_card, write_vendor_card, write_customer_card, write_credit_card) import minigrid.error import minigrid.models as models @@ -52,6 +53,7 @@ 'B': 'Customer ID Card', 'C': 'Credit Card', 'D': 'Maintenance Card', + 'E': 'Blank Card', } @@ -60,6 +62,7 @@ 'B': 'Customer User ID', 'C': 'Credit Amount', 'D': 'Maintenance Card ID', + 'E': 'Card Type', } @@ -321,6 +324,12 @@ def get(self): http_protocol = 'https' if options.minigrid_https else 'http' self.render('cards.html', http_protocol=http_protocol) + @tornado.web.authenticated + def post(self): + """Erase card.""" + erase_card(self.session, cache) + self.redirect(f'/cards') + class MinigridHandler(BaseHandler): """Handlers for a minigrid view.""" @@ -807,12 +816,19 @@ def _pack_into_dict(session, binary): if system_id == 'up': logging.info(f'Operator Box is {system_id}') return json_encode(result) + else: + cache.set('device_active', 1, 10) + cache.set('received_info', json_encode(result), 10) card_type = sector_1[4:5].decode('ascii') logging.info(f'Card Type: {card_type}') try: result['Card Type'] = _card_type_dict[card_type] except KeyError: if card_type == '\x00': + found = OrderedDict() + found['Card Type'] = 'Blank Card' + found['Connected Device'] = device_address.hex() + cache.set('received_info', json_encode(found), 10) raise minigrid.error.CardReadError('This card appears blank') raise minigrid.error.CardReadError( f'This card appears to have the invalid card type {card_type}') @@ -1033,6 +1049,15 @@ def _verify_written_card(session): mc_maintenance_card_card_id=mcid, )) cache.delete('write_info') + elif type == 'E': # Blank card + future = write_result['future_time'] + logging.info(f'future: {future}') + if int(future) > int(time.time()): + notify['notification'] = 'Card Blank' + notify['type'] = 'alert-success' + cache.set('notification', json_encode(notify), 10) + logging.info('Card Erased') + cache.delete('write_info') else: # Error case for card type notify['notification'] = 'Invalid Card Type' diff --git a/minigrid/templates/cards.html b/minigrid/templates/cards.html index a9fb7d7..0510ecd 100644 --- a/minigrid/templates/cards.html +++ b/minigrid/templates/cards.html @@ -1,17 +1,36 @@ {% extends 'base.html' %} {% block body %} +
+
{% if message is not None %}

{{ message }}

{% end %}

Read and validate cards:

+
+
+ Device Info +
+
+
Card Info
+
+
+ {% module xsrf_form_html() %} + + {% if device_active %} + + {% else %} + + {% end %} +
+
@@ -19,6 +38,6 @@

Read and validate cards:

- + {% end %} diff --git a/prod/docker-compose.yml b/prod/docker-compose.yml index d515931..4668daa 100644 --- a/prod/docker-compose.yml +++ b/prod/docker-compose.yml @@ -1,7 +1,7 @@ version: '2' services: minigrid: - image: selcolumbia/minigrid-server:0.3.2 + image: selcolumbia/minigrid-server:0.3.3 command: ./prod/run.sh --db_host=db --redis_url=redis://redis:6379/0 --minigrid-website-url=https://www.example.com depends_on: - redis diff --git a/prod/install.sh b/prod/install.sh index 3a2cc24..4fb9775 100755 --- a/prod/install.sh +++ b/prod/install.sh @@ -1,5 +1,5 @@ #!/usr/bin/env sh -# Minigrid Server installer for version 0.3.2 +# Minigrid Server installer for version 0.3.3 set -e # Do you have docker installed? @@ -108,8 +108,8 @@ $SUDO openssl dhparam -out /etc/letsencrypt/live/$LETSENCRYPT_DIR/dhparam.pem 20 printf "========================================\n" printf " Generating configuration \n" printf "========================================\n" -$CURL -L https://raw.githubusercontent.com/SEL-Columbia/minigrid-server/0.3.2/prod/docker-compose.yml > docker-compose.yml -$CURL -L https://raw.githubusercontent.com/SEL-Columbia/minigrid-server/0.3.2/prod/nginx.conf > nginx.conf +$CURL -L https://raw.githubusercontent.com/SEL-Columbia/minigrid-server/0.3.3/prod/docker-compose.yml > docker-compose.yml +$CURL -L https://raw.githubusercontent.com/SEL-Columbia/minigrid-server/0.3.3/prod/nginx.conf > nginx.conf sed -i s/www.example.com/$LETSENCRYPT_DIR/g docker-compose.yml sed -i s/www.example.com/$LETSENCRYPT_DIR/g nginx.conf @@ -147,7 +147,7 @@ printf "========================================\n" # The --post-hook should just be docker restart $NGINX_CONTAINER_NAME... but # the container can't run the docker command properly. # So /tmp/renewed serves as a sentinel -CRON_CMD="mkdir -p /tmp/letsencrypt && "\ +CRON_CMD_1="mkdir -p /tmp/letsencrypt && "\ "docker run -i --rm --name certbot"\ " -v /etc/letsencrypt:/etc/letsencrypt:Z"\ " -v /var/lib/letsencrypt:/var/lib/letsencrypt:Z"\ @@ -155,7 +155,13 @@ CRON_CMD="mkdir -p /tmp/letsencrypt && "\ " -v /var/log/letsencrypt:/var/log/letsencrypt:Z"\ " quay.io/letsencrypt/letsencrypt renew --quiet --webroot --webroot-path /tmp/letsencrypt;"\ " docker restart $NGINX_CONTAINER_NAME" +# Backup database every week at 2:15 +DB_CONTAINER_NAME=$($DOCKER_COMPOSE ps | grep _db_ | cut -d' ' -f1) +CRON_CMD_2="mkdir -p /db-bak && "\ +"docker exec $DB_CONTAINER_NAME pg_dump -U postgres minigrid > /db-bak/$LETSENCRYPT_DIR-db-$(date +%d-%m-%y).pg" # https://certbot.eff.org/#ubuntuxenial-nginx recommends running this twice a day on random minute within the hour -CRON_JOB="00 01,13 * * * sleep \$(expr \$RANDOM \% 59 \* 60); $CRON_CMD" -crontab -l | fgrep -i -v "$CRON_CMD" | { cat; echo "$CRON_JOB"; } | crontab - +CRON_JOB_1="00 01,13 * * * sleep \$(expr \$RANDOM \% 59 \* 60); $CRON_CMD_1" +CRON_JOB_2="15 2 * * 0 $CRON_CMD_2" +crontab -l | fgrep -i -v "$CRON_CMD_1" | { cat; echo "$CRON_JOB_1"; } | crontab - +crontab -l | fgrep -i -v "$CRON_CMD_2" | { cat; echo "$CRON_JOB_2"; } | crontab - crontab -l