Skip to content

Commit

Permalink
Get rid of pysftp, it was pretty broken, now use paramiko directly
Browse files Browse the repository at this point in the history
  • Loading branch information
hiviah committed Sep 16, 2023
1 parent 31e4549 commit 30ca988
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
10 changes: 8 additions & 2 deletions README.md
Expand Up @@ -4,8 +4,11 @@ This is an access-control system implementation via contactless ISO 14443A cards
and a PN53x-based reader. So you basically swipe your card, and if it's in
database, the door unlocks.

We still run this at this day (2023-09-16) because porting to Python 3 and SWIG is
not that simple, especially the SWIG part.

It's a bit old project, so requires python 2 (didn't have time for porting). At least currently
(2010-05-28) still works on latest Raspberry 4 and Raspbian Buster.
(2023-09-16) still works on latest Raspberry 4 and Raspbian Buster.

Info about authorized users and their cards and keys is stored in sqlite database.

Expand All @@ -29,6 +32,9 @@ and panic trigger) or a cheap electromagnetic lock.
* Yubikey Neo HMAC-SHA1 - most safe option, uncloneable
* Mifare Desfire - Ed25519 signature of UID (currently no known clones available; although some features could be cloned,
it's not enough for anyone to create such partial clones)
* working Mifare Desfire clones are nowhere to be seen in 2023, even though
the datasheet was leaked loooong time ago (adding encryption wouldn't be so
hard with `libfreefare`)

Test code is also provided to get payment signature (cryptogram) from Visa and Mastercard, but it's not used.

Expand Down Expand Up @@ -63,7 +69,7 @@ You need just to run `make`. Additional dependencies:
- [SWIG version 2](http://www.swig.org/) - to generate Python-C++ bindings, SWIG 3 is known to cause segfaults sometimes
- [WiringPi2 pythonic binding](https://github.com/WiringPi/WiringPi2-Python) (for switching lock on Raspberry), install from pip, `pip install wiringpi`
- [python-irc](https://pypi.python.org/pypi/irc) >= 16.0, use "pip install irc", the one in repos is old
- [pysftp](https://pypi.org/project/pysftp/) - for uploading SpaceAPI-formatted status to some host
- [paramiko](https://pypi.org/project/paramiko/) - for uploading SpaceAPI-formatted status to some host
- optional runtime dependency, not needed unless you set SFTP SpaceAPI upload to true

All dependencies can be installed on Ubuntu or Debian/Raspbian via:
Expand Down
43 changes: 37 additions & 6 deletions brmdoor_nfc_daemon.py
Expand Up @@ -382,21 +382,52 @@ def upload(self, isOpen):
:param isOpen - whether space is opened.
:raises paramiko.ssh_exception.SSHException when upload fails (timeout, can't connect, host key mismatch...)
"""
import pysftp
import paramiko
dirname, targetFname = os.path.split(self.config.sftpDestFile)

spaceApiJson = json.load(file("spaceapi_template.json"))
spaceApiJson["state"] = {"open": isOpen, "lastchange": time.time()}

with tempfile.NamedTemporaryFile() as tf:
log_paramiko = logging.getLogger("paramiko")
if log_paramiko:
log_paramiko.setLevel(logging.WARNING)

json.dump(spaceApiJson, tf, indent=4, ensure_ascii=True, encoding='utf-8')
tf.flush()
localFilename = tf.name
with pysftp.Connection(self.config.sftpHost, username=self.config.sftpUsername, port=self.config.sftpPort,
private_key=self.config.sftpKey) as sftp:
sftp.timeout = 15
with sftp.cd(dirname):
sftp.put(localFilename, remotepath=targetFname)

pkey = None
ssh = None
sftp = None

for pkey_class in (paramiko.RSAKey, paramiko.DSSKey, paramiko.ECDSAKey, paramiko.Ed25519Key):
try:
pkey = pkey_class.from_private_key_file(self.config.sftpKey)
logging.debug("Loaded SSH key of type %s", pkey_class)
break
except paramiko.ssh_exception.SSHException:
pass

if pkey is None:
logging.error("Failed to load private SSH key", self.config.sftpKey)
raise paramiko.ssh_exception.SSHException("Can't read private SSH key")

try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(self.config.sftpHost, username=self.config.sftpUsername, pkey=pkey, timeout=20)
sftp = ssh.open_sftp()

sftp.chdir(dirname)
sftp.put(localFilename, targetFname)

finally:
if sftp:
sftp.close()

if ssh:
ssh.close()


class OpenSwitchThread(threading.Thread):
Expand Down

0 comments on commit 30ca988

Please sign in to comment.