def test_simple(): cfg = ConfigParser.RawConfigParser() cfg.readfp(StringIO("""\ [access *] users = @bar xyzzy [group bar] users = quux thud """)) got = decide_recipients.decide_recipients(cfg, 'some/path') eq(sorted(got), sorted(['quux', 'thud', 'xyzzy']))
def verify(cfg, path): """ Generates a list of problems, each item a `VerifyResult`; empty list means everything is good. """ for relpath, path in walk.walk(cfg=cfg, path=path): log.debug('Verifying file: %s', relpath) ok = True result = VerifyResult( path=relpath, extra=set(), missing=set(), unknown_keys=set(), unknown_fingerprints=set(), ) want = decide_recipients.decide_recipients( cfg=cfg, path=relpath, ) want = set(want) log.debug('Expecting recipients: %s', ' '.join(sorted(want))) keyids = extract_recipients.extract_recipients(path) keyids = set(keyids) log.debug('Got recipient keyids: %s', ' '.join(keyids)) # Keyids can collide; that means a message may (to us) # look like it's encrypted to Bob, but in reality it's # encrypted to Mallory. This attack requires tricking the # person encrypting it to choosing the wrong key; if you # use "sekrit set", the recipient will be chosen by # fingerprint, and thus this attack is most likely # infeasible. Hence, we will just assume the keyids # extracted above map simply to our known # fingerprints/users. fprs = set() for keyid in keyids: fpr = keyid_to_fingerprint.keyid_to_fingerprint(keyid) if fpr is None: log.critical( '%s: Unexpected recipient keyid: %r', relpath, keyid, ) result.unknown_keys.add(keyid) ok = False else: fprs.add(fpr) log.debug('Got recipient fingerprints: %s', ' '.join(fprs)) got_users = set() for fpr in fprs: user = map_fpr_to_user.map_fpr_to_user(cfg, fpr) if user is None: log.critical( '%s: Unknown recipient fingerprint: %r', relpath, fpr, ) result.unknown_fingerprints.add(fpr) ok = False else: got_users.add(user) log.debug('Got recipients: %s', ' '.join(sorted(got_users))) extra = got_users - want if extra: log.critical( '%s: Unexpected recipients: %s', relpath, ' '.join(sorted(extra)), ) result.extra.update(extra) ok = False missing = want - got_users if missing: log.error( '%s: Missing recipients: %s', relpath, ' '.join(sorted(missing)), ) result.missing.update(missing) ok = False if ok: log.info('%s: ok: %s', relpath, ' '.join(sorted(got_users))) else: log.error('%s: bad', relpath) yield result
def set_secret(cfg, path): users = decide_recipients.decide_recipients(cfg, path) users = list(users) if not users: raise RuntimeError('Nobody to encrypt to: %s', path) fingerprints = [ user_to_fpr.user_to_fpr(cfg=cfg, user=user) for user in users ] if not fingerprints: raise RuntimeError('No fingerprints found for users: %s', ' '.join(users)) gpg = GnuPGInterface.GnuPG() gpg.options.armor = 1 gpg.options.meta_interactive = 0 gpg.options.recipients = fingerprints if not os.isatty(sys.stdin.fileno()): # redirected from file / pipe, read passphrase from there secret1 = sys.stdin.readline() secret1 = secret1.rstrip('\n') else: secret1 = prompt(message='Passphrase for %s' % path) secret2 = prompt(message='Repeat pass for %s' % path) if secret1 != secret2: del secret1 del secret2 print >>sys.stderr, '%s: Passphrases do not match.' % sys.argv[0] sys.exit(1) del secret2 tmp = '{path}.{pid}.tmp'.format( path=path, pid=os.getpid(), ) with file(tmp, 'w') as fp: try: proc = gpg.run( [ '--encrypt', '--for-your-eyes-only', '--trust-mode=always', ], create_fhs=['stdin'], attach_fhs=dict( stdout=fp, logger=sys.stderr, ), ) proc.handles['stdin'].write(secret1) del secret1 proc.handles['stdin'].close() try: proc.wait() except IOError, e: print >>sys.stderr, '%s: gnupg: %s' % (sys.argv[0], e) sys.exit(1) except: try: os.unlink(tmp) except: pass raise os.rename(tmp, path) print 'Encrypted to:' for uid in users: print '\t%s' % uid