Initial commit

main
beucismis 3 years ago
parent 6ba1e15b0b
commit cbcc1fff14
  1. 7
      MANIFEST.in
  2. 3
      README.md
  3. 52
      backupill/__init__.py
  4. 110
      backupill/backuper.py
  5. 3
      backupill/gui/README.md
  6. 0
      backupill/gui/__init__.py
  7. 0
      backupill/gui/workbench.py
  8. 4
      dev-requirements.txt
  9. 0
      docs/README.md
  10. 4
      requirements.txt
  11. 34
      setup.py
  12. 52
      test/test.asc
  13. BIN
      test/test.asc.pdf
  14. 11
      test/test.py

@ -0,0 +1,7 @@
image: python:latest
test:
stage: test
script:
- pip3 install pytest
- python3 -m pytest -v

@ -0,0 +1,3 @@
# backupill
Backupill (Backup Pill), generates barcoded PDF to backup text files on paper. Designed to backup ASCII-armored GnuPG and SSH key files and ciphertext.

@ -0,0 +1,52 @@
#!/usr/bin/python3
"""
Copyright (C) 2021- beucismis
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 3 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, see <https://www.gnu.org/licenses/>.
"""
import os
import click
from .backuper import Pill
__version__ = "0.1.0"
__license__ = "GPL-3.0"
__author__ = "Adil Gurbuz"
__contact__ = "beucismis@tutamail.com"
__source__ = "https://github.com/beucismis/backupill"
__description__ = "Generates barcoded PDF to backup text files on paper."
@click.version_option(version=__version__)
@click.option("-f", "--file", help="ASC file path.")
@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
def main(file):
"""Generates barcoded PDF to backup text files on paper.
https://github.com/beucismis/backupill
"""
if file:
if not os.path.isfile(file):
click.echo("File '{}' not found!".format(file))
exit()
Pill(asc_file=file).generate_backup()
click.echo("Done!")
else:
click.echo("Usage: packupill -f FILENAME.asc")
if __name__ == "__main__":
main()

@ -0,0 +1,110 @@
import os
# import re
import qrcode
# import hashlib
import logging
from pyx import *
# import subprocess
from tempfile import mkstemp
from datetime import datetime
TEXT_X_OFFSET = 0.6
TEXT_Y_OFFSET = 8.2
PLAINTEXT_MAXLINECHARS = 73
QRCODE_HEIGHT = 8
QRCODE_PER_PAGE = 6
QRCODE_MAX_BYTE = 140
QRCODE_X_POS = [1.5, 11, 1.5, 11, 1.5, 11]
QRCODE_Y_POS = [18.7, 18.7, 10, 10, 1.2, 1.2]
PF_STR = "A4"
PF_OBJ = document.paperformat.A4
# suppressing all the warnings
for name in logging.Logger.manager.loggerDict.keys():
logging.getLogger(name).setLevel(logging.CRITICAL)
class Pill:
def __init__(self, asc_file):
self.ASC_FILE = asc_file
self.pageno = 0
self.pageid = 0
self.code_blocks = []
self._init_pdf()
with open(asc_file) as file:
self.ASCDATA = file.read()
def _init_pdf(self):
unit.set(defaultunit="cm")
self.pdf = document.document()
def _generate_barcode(self, chunkdata):
qr = qrcode.QRCode(
version=1,
border=4,
box_size=10,
error_correction=qrcode.constants.ERROR_CORRECT_L,
)
qr.add_data(chunkdata)
qr.make(fit=True)
im = qr.make_image(fill_color="black", back_color="white")
return im
def _finish_page(self, pdf, canvas, pageno):
canvas.text(10, 0.6, "Page {}".format(pageno + 1))
pdf.append(document.page(canvas, paperformat=PF_OBJ, fittosize=0, centered=0))
def generate_backup(self):
chunkdata = "^1 "
c = canvas.canvas()
for char in list(self.ASCDATA):
if len(chunkdata) + 1 > QRCODE_MAX_BYTE:
self.code_blocks.append(self._generate_barcode(chunkdata))
chunkdata = "^" + str(len(self.code_blocks) + 1) + " "
chunkdata += char
self.code_blocks.append(self._generate_barcode(chunkdata))
for bc in range(len(self.code_blocks)):
if self.pageid >= QRCODE_PER_PAGE:
self._finish_page(self.pdf, c, self.pageno)
c = canvas.canvas()
self.pageno += 1
self.pageid = 0
c.text(
QRCODE_X_POS[self.pageid] + TEXT_X_OFFSET,
QRCODE_Y_POS[self.pageid] + TEXT_Y_OFFSET,
"{} ({}/{})".format(
text.escapestring(self.ASC_FILE), bc + 1, len(self.code_blocks)
),
)
c.insert(
bitmap.bitmap(
QRCODE_X_POS[self.pageid],
QRCODE_Y_POS[self.pageid],
self.code_blocks[bc],
height=QRCODE_HEIGHT,
)
)
self.pageid += 1
self._finish_page(self.pdf, c, self.pageno)
fd, temp_barcode_path = mkstemp(".pdf", "qr_", ".")
self.pdf.writetofile(temp_barcode_path)
os.rename(temp_barcode_path.split(os.sep)[-1], self.ASC_FILE + ".pdf")

@ -0,0 +1,3 @@
# backupill-gui

@ -0,0 +1,4 @@
twine
black
pytest
virtualenv

@ -0,0 +1,4 @@
pyx
click
qrcode
pillow

@ -0,0 +1,34 @@
import sys
import backupill as bp
from setuptools import setup
if sys.version_info < (3, 5):
raise RuntimeError("backupill requires Python 3.5 or later")
with open("README.md") as f:
long_description = f.read()
setup(
name="backupill",
packages=["backupill"],
version=bp.__version__,
description=bp.__description__,
long_description=long_description,
long_description_content_type="text/markdown",
url=bp.__source__,
author=bp.__author__,
author_email=bp.__contact__,
license=bp.__license__,
classifiers=[],
platforms=["Linux"],
python_requires=">=3.5",
install_requires=["pyx", "click", "qrcode"],
keywords=[],
entry_points={
"console_scripts": [
"backupill = backupill:main",
],
},
)

@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
dRYbPoN2pT4P
=XYxH
-----END PGP PUBLIC KEY BLOCK-----

Binary file not shown.

@ -0,0 +1,11 @@
import os
import pytest
from backupill import Pill
this_dir, this_filename = os.path.split(__file__)
def test_generate_backup():
pill = Pill(asc_file=os.path.join(this_dir, "test.asc"))
pill.generate_backup()
Loading…
Cancel
Save