Commit a85883dd authored by Arturo Hernandez's avatar Arturo Hernandez

functional commit

parent 6d8bf42c
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env
pip-log.txt
pip-delete-this-directory.txt
.tox
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
*.log
.git
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
cert/
certs/
# Pull base image
FROM python:3.6-slim
# Set environment varibles
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Set work directory
WORKDIR /code
# Copy install
ADD requirements.txt /code/
# Install dependencies
RUN apt-get update && apt-get install -y psmisc pcscd libpcsclite-dev udev \
&& savedAptMark="$(apt-mark showmanual)" \
&& apt-get install -y --no-install-recommends git \
python3-setuptools python3-dev python3-augeas gcc swig \
&& pip install --upgrade pip \
&& pip install -r requirements.txt \
&& apt-mark auto '.*' > /dev/null \
&& apt-mark manual $savedAptMark \
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
&& rm -rf /var/lib/apt/lists/*
#copy base files
run mkdir -p /code/cert/
ADD ./cert/server.crt /code/cert/
ADD ./cert/server.key /code/cert/
ADD src /code/src/
ENV LOGFILE /dev/stdout
ENV MST_PORT 8000
ENV MST_CERT cert/server.crt
ENV MST_KEY cert/server.key
ENV DEBUG False
CMD python3 src/main.py
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
future = "*"
pyscard = "*"
tornado = "*"
[dev-packages]
[requires]
python_version = "3.8"
Clonar repositorio
```sh
git -c http.sslVerify=false clone --recurse-submodules --depth=1 https://gitlab.agetic.gob.bo/ahernandez/microservicio_tarjetas.git
cd microservicio_tarjetas
```
Ingresar a la carpeta de docker
```sh
cd docker
```
Construir la imagen:
```sh
./build_image_1.0.0.sh
```
### 1. Levantar sin PCSCD (ordenaror nuevo - limpio)
Iniciar docker con acceso a usb e iniciar el monitor usb (o iniciar manualmente pcscd en el contenedor)
```sh
docker run --rm -d -p 127.0.0.1:8000:8000 --device=/dev/bus/usb --device-cgroup-rule='c 189:* rmw' --name agetic_mst agetic_mst:1.0.0
# luego iniciar el monitor USB (inicia pcscd en el cliente y permite reconectar)
./refresh_usb.sh # requiere python
# opcionalmente puede ejectuar una vez
# docker exec -t agetic_mst bash -c 'pcscd'
```
y revisar el log con
```sh
docker logs agetic_mst -f
```
puede detenerlo con:
```sh
docker stop agetic_mst
```
### 2. Compartir PCSCD
Requiere `pcscd libpcsclite-dev ` instalado en el anfitrion, permite reconectar sin necesidad de reiniciar pcscd
```sh
docker run --rm -d -p 127.0.0.1:8000:8000 -v /var/run/pcscd/pcscd.comm:/var/run/pcscd/pcscd.comm --name agetic_mst agetic_mst:1.0.0
```
y revisar el log con
```sh
docker logs agetic_mst -f
```
puede detenerlo con:
```sh
docker stop agetic_mst
```
#### Opcional:
ejecutar
```sh
run_image_share.sh
```
### develop
para compartir la carpeta `src/` de la aplicación en tiempo real
```sh
# opción 1. ordenador sin pcscd
#desde la carpeta docker
docker run --rm -p 127.0.0.1:8000:8000 -i -t -v $(dirname $(pwd))/src:/code/src/ --device=/dev/bus/usb --device-cgroup-rule='c 189:* rmw' --env DEBUG=True --name agetic_mst agetic_mst:1.0.0
#ejecutar en otra ventana el monitor usb
./refresh_usb.sh
# opción 2. compartiendo pcscd
#desde la carpeta docker
docker run --rm -p 127.0.0.1:8000:8000 -i -t -v $(dirname $(pwd))/src:/code/src/ -v /var/run/pcscd/pcscd.comm:/var/run/pcscd/pcscd.comm --env DEBUG=True --name agetic_mst agetic_mst:1.0.0
#opcíón a la opción 2: ejecutar
./develop_share.sh
# opcional levantar bash
docker exec -i -t agetic_mst bash
```
#!/bin/bash
#!/usr/bin/env bash
IMAGE_NAME="agetic_mst"
SRC=$(cd $(dirname "$0"); cd ..; pwd)
cd $SRC
#docker ps -a | awk '{ print $1,$2 }' | grep sedem_mst:1.0.0 | awk '{print $1 }' | xargs -I {} docker rm {}
docker ps -a | grep "${IMAGE_NAME}:1.0.0" | awk '{print $1}' | xargs docker rm
#docker rmi zkcluster
docker images -a | grep "${IMAGE_NAME}" | awk '{print $3}' | xargs docker rmi
docker build -t "${IMAGE_NAME}":1.0.0 -f docker/Dockerfile .
#!/bin/bash
#!/usr/bin/env bash
IMAGE_NAME="agetic_mst"
IMAGE_VERSION="1.0.0"
SRC=$(cd $(dirname "$0"); cd ..; pwd)
cd $SRC
cd docker
# opción 2. compartiendo pcscd
#desde la carpeta docker
echo "Starting develop mode (following ./src/ changes) with shared pcsdc..."
echo "Press Ctrl+C or 'docker stop ${IMAGE_NAME}' to exit"
docker run --rm -p 127.0.0.1:8000:8000 -i -t -v $(dirname $(pwd))/src:/code/src/ -v /var/run/pcscd/pcscd.comm:/var/run/pcscd/pcscd.comm --env DEBUG=True --name ${IMAGE_NAME} ${IMAGE_NAME}:${IMAGE_VERSION}
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#original from https://github.com/th3mis/docker-usb-sync
import syslog
import subprocess
import os
def log(message):
print(message)
def exec_in_container(cmd, name="agetic_mst"):
log( "docker exec {} bash -c '{}'".format(name, cmd))
return subprocess.check_output(
"docker exec {} bash -c '{}'".format(name, cmd),
universal_newlines=True,
shell=True
)
root_dev = "/dev/bus/usb"
for bus_num in os.listdir(root_dev):
bus_path = os.path.join(root_dev, bus_num)
container_devices = exec_in_container("ls " + bus_path).split("\n")
host_devices = os.listdir(bus_path)
# remove dead links
for device in container_devices:
if device and device not in host_devices:
log("removing {}".format(device))
exec_in_container("rm " + os.path.join(bus_path, device))
# add new links
for device in host_devices:
if device not in container_devices:
stat = os.stat(os.path.join(bus_path, device))
log("adding {}".format(device))
cmd = "mknod {device} c {major} {minor}".format(
device=os.path.join(bus_path, device),
major=os.major(stat.st_rdev),
minor=os.minor(stat.st_rdev)
)
exec_in_container(cmd)
#!/bin/bash
#Set the idVendor/idProduct that we are interested in
idVendor="076b"
idProduct="5022"
idString="${idVendor}:${idProduct}"
#Check if the device we are interested in is already connected
#before we start listing in a loop
devWasConnected=$(lsusb | grep "ID ${idString}" | wc -l)
./docker-usb-sync.py
docker exec -t agetic_mst bash -c 'pcscd'
inotifywait -r -m /dev/bus/usb -e CREATE -e DELETE | while read e
do
#echo $e
./docker-usb-sync.py
echo "restarting pcscd..."
docker exec -t agetic_mst bash -c 'killall pcscd'
docker exec -t agetic_mst bash -c 'pcscd'
done
#!/bin/bash
#!/usr/bin/env bash
IMAGE_NAME="agetic_mst"
IMAGE_VERSION="1.0.0"
SRC=$(cd $(dirname "$0"); cd ..; pwd)
cd $SRC
cd docker
trap ctrl_c INT
function ctrl_c() {
echo "** Stopping docker image..."
docker stop ${IMAGE_NAME}
}
echo "Starting image with shared pcscd..."
# opción 2. compartiendo pcscd
docker run --rm -d -p 127.0.0.1:8000:8000 -v /var/run/pcscd/pcscd.comm:/var/run/pcscd/pcscd.comm --name ${IMAGE_NAME} ${IMAGE_NAME}:${IMAGE_VERSION} && echo "Following logs..." && docker logs ${IMAGE_NAME} -f
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env
pip-log.txt
pip-delete-this-directory.txt
.tox
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
*.log
.git
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
def str2bool(cadena):
"""retorna un booleano a partir de una cadena [yes,true,t] o numero 1 """
return cadena.lower() in ("yes", "true", "t", "1")
MST_PORT = int(os.environ.get("MST_PORT", '8000'))
MST_CERT = os.environ.get("MST_CERT", 'cert/server.crt')
MST_KEY = os.environ.get("MST_KEY", 'cert/server.key')
DEBUG = str2bool(os.environ.get("DEBUG", 'False'))
if __name__ == '__main__':
print("configs")
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import logging
import datetime
from threading import Thread
import tornado.httpserver
import tornado.ioloop
import tornado.web
from smartcard.util import toHexString, toASCIIString, padd
#change CWD to parent of src/
os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
#print (os.getcwd())
#configuración inicia de bitácora
LEVEL_NAME = os.getenv('LOGLEVEL', "INFO").upper()
if hasattr(logging, LEVEL_NAME):
LOG_LEVEL = getattr(logging, LEVEL_NAME)
else:
LOG_LEVEL = logging.INFO # default
if __name__ == '__main__': #logging para los modulos
logging.addLevelName(logging.DEBUG, "\033[1;36m%s\033[1;0m" % "DBG")
logging.addLevelName(logging.INFO, "\033[1;34m%s\033[1;0m" % "INF")
logging.addLevelName(logging.WARNING, "\033[1;33m%s\033[1;0m" % "WRN")
logging.addLevelName(logging.ERROR, "\033[1;41m%s\033[1;0m" % "ERR")
LOG_FILE = os.getenv('LOGFILE', 'bitacora.log')
if not os.path.isfile(LOG_FILE):
try:
open(LOG_FILE, 'a').close()
except:
pass #can't create log file
if os.path.isfile(LOG_FILE) and os.access(LOG_FILE, os.W_OK):
logging.basicConfig(
format='%(levelname)s %(asctime)s %(name)s - %(message)s',
datefmt='\033[1;37m%Y-%m-%d %H:%M:%S\033[1;0m',
filename=LOG_FILE, level=LOG_LEVEL)
else:
logging.basicConfig(
format='%(levelname)s %(asctime)s %(name)s - %(message)s',
datefmt='\033[1;37m%Y-%m-%d %H:%M:%S\033[1;0m',
level=LOG_LEVEL)
print ("WRN: LOG to STDOUT")
LOGGER = logging.getLogger(__name__)
def handle_exception(exc_type, exc_value, exc_traceback):
"""captura excepciones en la misma bitácora"""
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
LOGGER.error("Uncaught exception",
exc_info=(exc_type, exc_value, exc_traceback))
sys.excepthook = handle_exception
INIT_OLD = Thread.__init__
def init(self, *args, **kwargs):
"""nuevo inicio con hook de captura de error para log"""
INIT_OLD(self, *args, **kwargs)
run_old = self.run
def run_with_except_hook(*args, **kw):
"""run con hook para captura de error"""
try:
run_old(*args, **kw)
except (KeyboardInterrupt, SystemExit):
raise # sale finalmente
except:
sys.excepthook(*sys.exc_info()) #dispara hook
self.run = run_with_except_hook
Thread.__init__ = init
from parseATR import parseATR #https://github.com/LudovicRousseau/pyscard-contrib
import config
from rfid import OMNIKEYCard, OMNIKEYException
class MainHandler(tornado.web.RequestHandler):
def get(self):
LOGGER.debug(self.request)
self.write("Hello, world")
class ReadHandler(tornado.web.RequestHandler):
def set_default_headers(self):
self.set_header("Access-Control-Allow-Origin", "*")
self.set_header('Access-Control-Allow-Methods', 'GET, OPTIONS')
self.set_header("Access-Control-Allow-Headers", "x-requested-with,access-control-allow-origin,authorization,content-type")
remote_ip = self.request.headers.get("X-Real-IP") or \
self.request.headers.get("X-Forwarded-For") or \
self.request.remote_ip
LOGGER.info("{} from {}".format(self.request.method, remote_ip))
def options(self):
# no body
self.set_status(204)
self.finish()
def get(self):
print("reading card...")
try:
card = OMNIKEYCard.connect()
except OMNIKEYException as e:
LOGGER.info("Error: {}".format(e))
self.write({"error": str(e)})
else:
atr = toHexString(card.get_ATR())
LOGGER.info('ATR: {}'.format(atr))
uid = card.get_UID()
LOGGER.info('UUIDHex: {}'.format(toHexString(uid, 1)))
atr_match = []
atr_possible = []
found = parseATR.match_atr_differentiated(atr, "src/parseATR/smartcard_list.txt")
if found:
if atr in found:
for d in found[atr]:
atr_match.append(str(d))
del found[atr]
for a in found:
for d in found[a]:
atr_possible.append(str(d))
self.write({
'reader': str(card.reader),
'ATR': atr,
'ATR_match': atr_match,
'ATR_possible': atr_possible,
'UUIDHex': toHexString(uid, 1),
'message': 'OK'
})
class IndexHandler(tornado.web.RequestHandler):
def get(self, url):
LOGGER.info("via h")
self.render('index.html')
class TestHandler(tornado.web.RequestHandler):
def get(self, url):
LOGGER.info("via h")
self.render('test.html')
def make_app():
return tornado.web.Application([
(r"/(index.*)?", IndexHandler),
(r"/api/?", TestHandler),
(r"/api/read-card/?", ReadHandler),
(r"/api/write-card/?", MainHandler),
(r"/mst_cert.crt()",tornado.web.StaticFileHandler, {"path": config.MST_CERT}),
(r"/(.*)",tornado.web.StaticFileHandler, {"path": "src/www"},), #path fixed to top
], template_path="src/www", debug=config.DEBUG) #path fixed to top
if __name__ == "__main__":
app = make_app()
app.listen(config.MST_PORT, ssl_options={
"certfile": config.MST_CERT,
"keyfile": config.MST_KEY,
})
print(' __ ')
print(' / _) ')
print(' _/\\/\\/\\_/ / ')
print(' _| / ')
print(' _| ( | ( | ')
print('/__.-\'|_|--|_| AHC')
print('')
print("Iniciado en https://127.0.0.1:{}".format(config.MST_PORT))
LOGGER.info("App Listening on https://127.0.0.1:{}".format(config.MST_PORT))
tornado.ioloop.IOLoop.current().start()
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env
pip-log.txt
pip-delete-this-directory.txt
.tox
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
*.log
.git
parseATR
########
This Python code parses a smart card ATR and display the result.
Author
******
Ludovic Rousseau <ludovic.rousseau@free.fr>
Licence
*******
Copyright (C) 2009-2015 Ludovic Rousseau
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
parseATR.py
***********
Display the result as text
Usage:
$ ./parseATR.py 3B A7 00 40 18 80 65 A2 08 01 01 52
parseATRhtml.py
***************
Display the result as HTML
Usage:
$ ./parseATRhtml.py 3B A7 00 40 18 80 65 A2 08 01 01 52
This diff is collapsed.
#! /usr/bin/env python
"""
parseATRhtml: convert an ATR in a (HTML) human readable format
Copyright (C) 2009-2016 Ludovic Rousseau
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
from parseATR import parseATR, atr_display_html
header = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ATR Parsing</title>
<style type="text/css">
span.data{color: blue;}
span.format{color: magenta;}
table, th, td { border: 1px solid black; text-align: left; }
.marge { margin-left: 1em; }
</style>
</head>
<body>"""