sign_file.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #! /usr/bin/env python
  2. """
  3. A script that creates signed Python files.
  4. """
  5. from __future__ import print_function
  6. import os
  7. import argparse
  8. import subprocess
  9. def get_file_encoding(filename):
  10. """
  11. Get the file encoding for the file with the given filename
  12. """
  13. with open(filename, 'rb') as fp:
  14. # The encoding is usually specified on the second line
  15. txt = fp.read().splitlines()[1]
  16. txt = txt.decode('utf-8')
  17. if 'encoding' in txt:
  18. encoding = txt.split()[-1]
  19. else:
  20. encoding = 'utf-8' # default
  21. return str(encoding)
  22. def sign_file_and_get_sig(filename, encoding):
  23. """
  24. Sign the file and get the signature
  25. """
  26. cmd = 'gpg -bass {}'.format(filename)
  27. ret = subprocess.Popen(cmd, shell=True).wait()
  28. print ('-> %r' % cmd)
  29. if ret:
  30. raise ValueError('Could not sign the file!')
  31. with open('{}.asc'.format(filename), 'rb') as fp:
  32. sig = fp.read()
  33. try:
  34. os.remove('{}.asc'.format(filename))
  35. except OSError:
  36. pass
  37. sig = sig.decode(encoding)
  38. sig = sig.replace('\r', '').replace('\n', '\\n')
  39. sig = sig.encode(encoding)
  40. return sig
  41. def sign_original_file(filename, encoding):
  42. """
  43. Sign the original file
  44. """
  45. sig = sign_file_and_get_sig(filename, encoding)
  46. with open(filename, 'ab') as outfile:
  47. outfile.write('#'.encode(encoding))
  48. outfile.write(sig)
  49. outfile.write('\n'.encode(encoding))
  50. def create_signed_file(filename, encoding):
  51. """
  52. Create a signed file
  53. """
  54. sig = sign_file_and_get_sig(filename, encoding)
  55. name, extension = os.path.splitext(filename)
  56. new_file_name = '{}_signed{}'.format(name, extension)
  57. with open(new_file_name, 'wb') as outfile, \
  58. open(filename, 'rb') as infile:
  59. txt = infile.read()
  60. outfile.write(txt)
  61. outfile.write('#'.encode(encoding))
  62. outfile.write(sig)
  63. outfile.write('\n'.encode(encoding))
  64. def parse_args():
  65. parser = argparse.ArgumentParser()
  66. parser.add_argument('filenames', action='store', nargs='+',
  67. help='Files you wish to sign')
  68. parser.add_argument('--overwrite', action='store_true',
  69. dest='overwrite', default=False,
  70. help='Overwrite the original file'
  71. ' (sign the original file)')
  72. opts = parser.parse_args()
  73. return opts
  74. if __name__ == '__main__':
  75. opts = parse_args()
  76. for filename in opts.filenames:
  77. encoding = get_file_encoding(filename)
  78. if opts.overwrite:
  79. sign_original_file(filename, encoding)
  80. else:
  81. create_signed_file(filename, encoding)