summaryrefslogtreecommitdiff
path: root/lib/thandy/util.py
blob: f2bac173f684bab8a81892a31085c3bbf0cffbd6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# Copyright 2008 The Tor Project, Inc.  See LICENSE for licensing information.

import os
import sys
import tempfile
import random

try:
    import json
except ImportError:
    import simplejson as json

try:
    import _winreg
except ImportError:
    _winreg = None

import thandy.formats
import thandy.keys
import thandy.master_keys

def moveFile(fromLocation, toLocation):
    """Move the file from fromLocation to toLocation, removing any file
       in toLocation.
    """
    if sys.platform in ('cygwin', 'win32'):
        # Win32 doesn't let rename replace an existing file.
        try:
            os.unlink(toLocation)
        except OSError:
            pass

    os.rename(fromLocation, toLocation)

def replaceFile(fname, contents, textMode=False):
    """overwrite the file in 'fname' atomically with the content of 'contents'
    """
    dir, prefix = os.path.split(fname)
    fd, fname_tmp = tempfile.mkstemp(prefix=prefix, dir=dir, text=textMode)

    try:
        os.write(fd, contents)
    finally:
        os.close(fd)

    moveFile(fname_tmp, fname)

def userFilename(name):
    try:
        base = os.environ["THANDY_HOME"]
    except KeyError:
        base = "~/.thandy"
    base = os.path.expanduser(base)
    if not os.path.exists(base):
        os.makedirs(base, 0700)
    return os.path.join(base, name)

def ensureParentDir(name):
    """DOCDOC"""
    directory = os.path.split(name)[0]
    if not os.path.exists(directory):
        os.makedirs(directory, 0700)

def getKeylist(keys_fname, checkKeys=True):
    import thandy.master_keys

    keydb = thandy.formats.Keylist()

    for key in thandy.master_keys.MASTER_KEYS:
        keydb.addKey(thandy.keys.RSAKey.fromJSon(key))

    user_keys = userFilename("preload_keys")
    if os.path.exists(user_keys):
        #XXXX somewhat roundabout.
        keylist = thandy.formats.makeKeylistObj(user_keys)
        keydb.addFromKeylist(keylist, allowMasterKeys=True)

    if keys_fname and os.path.exists(keys_fname):
        f = open(keys_fname, 'r')
        try:
            obj = json.load(f)
        finally:
            f.close()
        ss, role, path = thandy.formats.checkSignedObj(obj, keydb)
        if role != 'master':
            raise thandy.FormatException("%s wasn't a keylist."%keys_fname)
        if checkKeys and not ss.isValid():
            raise thandy.FormatException("%s not signed by enough master keys"%
                                         keys_fname)
        keydb.addFromKeylist(obj['signed'], allowMasterKeys=False)

    return keydb

def randChooseWeighted(lst):
    """Given a list of (weight,item) tuples, pick an item with
       probability proportional to its weight.
    """

    totalweight = sum(w for w,i in lst)
    position = random.uniform(0, totalweight)
    soFar = 0

    # We could use bisect here, but this is not going to be in the
    # critical path.  If it is, oops.
    for w,i in lst:
        soFar += w
        if position < soFar:
            return i

    return lst[-1][1]