1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from mediagoblin
import mg_globals
27 _log
= logging
.getLogger(__name__
)
29 # produces base64 alphabet
30 ALPHABET
= string
.ascii_letters
+ "-_"
32 # Use the system (hardware-based) random number generator if it exists.
33 # -- this optimization is lifted from Django
35 getrandbits
= random
.SystemRandom().getrandbits
36 except AttributeError:
37 getrandbits
= random
.getrandbits
39 # TODO: This should be attached to the MediaGoblinApp
43 def load_key(filename
):
45 key_file
= open(filename
)
47 __itsda_secret
= key_file
.read()
52 def create_key(key_dir
, key_filepath
):
54 old_umask
= os
.umask(0o77)
57 if not os
.path
.isdir(key_dir
):
59 _log
.info("Created %s", key_dir
)
60 key
= str(getrandbits(192))
61 key_file
= tempfile
.NamedTemporaryFile(dir=key_dir
, suffix
='.bin',
63 key_file
.write(key
.encode('ascii'))
65 os
.rename(key_file
.name
, key_filepath
)
69 if (key_file
is not None) and (not key_file
.closed
):
71 os
.unlink(key_file
.name
)
73 _log
.info("Saved new key for It's Dangerous")
76 def setup_crypto(app_config
):
78 key_dir
= app_config
["crypto_path"]
79 key_filepath
= os
.path
.join(key_dir
, 'itsdangeroussecret.bin')
81 load_key(key_filepath
)
82 except IOError as error
:
83 if error
.errno
!= errno
.ENOENT
:
85 create_key(key_dir
, key_filepath
)
88 def get_timed_signer_url(namespace
):
90 This gives a basic signing/verifying object.
92 The namespace makes sure signed tokens can't be used in
93 a different area. Like using a forgot-password-token as
98 .. code-block:: python
101 TOKEN_VALID_DAYS = 10
104 _signer = get_timed_signer_url("session cookie")
105 def create_token(obj):
106 return _signer.dumps(obj)
107 def parse_token(token):
108 # This might raise an exception in case
109 # of an invalid token, or an expired token.
110 return _signer.loads(token, max_age=TOKEN_VALID_DAYS*24*3600)
113 http://pythonhosted.org/itsdangerous/#itsdangerous.URLSafeTimedSerializer
115 assert __itsda_secret
is not None
116 return itsdangerous
.URLSafeTimedSerializer(__itsda_secret
,
119 def random_string(length
, alphabet
=ALPHABET
):
120 """ Returns a URL safe base64 encoded crypographically strong string """
123 for i
in range(length
):
124 n
= getrandbits(6) # 6 bytes = 2^6 = 64
125 n
= divmod(n
, base
)[1]
126 rstring
+= alphabet
[n
]