OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 """A set of functions that provide persistence for secret keys. |
| 7 |
| 8 These keys are used in generating XSRF tokens, calling the CAPTCHA API, |
| 9 and validating that inbound emails are replies to notifications that |
| 10 we sent. |
| 11 |
| 12 Unlike other data stored in Monorail, this is kept in the GAE |
| 13 datastore rather than SQL because (1) it never needs to be used in |
| 14 combination with other SQL data, and (2) we may want to replicate |
| 15 issue content for various off-line reporting functionality, but we |
| 16 will never want to do that with these keys. A copy is also kept in |
| 17 memcache for faster access. |
| 18 |
| 19 When no secrets are found, a new Secrets entity is created and initialized |
| 20 with randomly generated values for XSRF and email keys. |
| 21 |
| 22 If these secret values ever need to change: |
| 23 (1) Make the change on the Google Cloud Console in the Cloud Datastore tab. |
| 24 (2) Flush memcache. |
| 25 """ |
| 26 |
| 27 import logging |
| 28 |
| 29 from google.appengine.api import memcache |
| 30 from google.appengine.ext import ndb |
| 31 |
| 32 import settings |
| 33 from framework import framework_helpers |
| 34 |
| 35 |
| 36 GLOBAL_KEY = 'secrets_singleton_key' |
| 37 |
| 38 |
| 39 class Secrets(ndb.Model): |
| 40 """Model for representing secret keys.""" |
| 41 # Keys we use to generate tokens. |
| 42 xsrf_key = ndb.StringProperty(required=True) |
| 43 email_key = ndb.StringProperty(required=True) |
| 44 |
| 45 # Keys for other APIs that we use. |
| 46 recaptcha_public_key = ndb.StringProperty() |
| 47 recaptcha_private_key = ndb.StringProperty() |
| 48 |
| 49 |
| 50 def MakeSecrets(): |
| 51 """Make a new Secrets model with random values for keys.""" |
| 52 secrets = Secrets(id=GLOBAL_KEY) |
| 53 secrets.xsrf_key = framework_helpers.MakeRandomKey() |
| 54 secrets.email_key = framework_helpers.MakeRandomKey() |
| 55 # Note that recaptcha keys are not generated. An admin |
| 56 # will need to set them via the Google Cloud Console. |
| 57 return secrets |
| 58 |
| 59 |
| 60 def GetSecrets(): |
| 61 """Get secret keys from memcache or datastore. Or, make new ones.""" |
| 62 secrets = memcache.get(GLOBAL_KEY) |
| 63 if secrets: |
| 64 return secrets |
| 65 |
| 66 secrets = Secrets.get_by_id(GLOBAL_KEY) |
| 67 if not secrets: |
| 68 secrets = MakeSecrets() |
| 69 secrets.put() |
| 70 |
| 71 memcache.set(GLOBAL_KEY, secrets) |
| 72 return secrets |
| 73 |
| 74 |
| 75 def GetXSRFKey(): |
| 76 """Return a secret key string used to generate XSRF tokens.""" |
| 77 return GetSecrets().xsrf_key |
| 78 |
| 79 |
| 80 def GetEmailKey(): |
| 81 """Return a secret key string used to generate email tokens.""" |
| 82 return GetSecrets().email_key |
| 83 |
| 84 |
| 85 def GetRecaptchaPublicKey(): |
| 86 """Return our public API key for reCAPTCHA.""" |
| 87 if settings.dev_mode: |
| 88 return '6LebzNMSAAAAAMY8b_FaZvp8wymUO5Jsa0pIX7HO' |
| 89 |
| 90 result = GetSecrets().recaptcha_public_key |
| 91 if not result: |
| 92 logging.warn('No recaptcha_public_key set. Get one at recaptcha.net.') |
| 93 logging.warn('Store it in Cloud Datastore via the Google Cloud Console.') |
| 94 |
| 95 return result |
| 96 |
| 97 |
| 98 def GetRecaptchaPrivateKey(): |
| 99 """Return our private API key for reCAPTCHA.""" |
| 100 if settings.dev_mode: |
| 101 return '6LebzNMSAAAAAHNVNiP2I7aNMv2AmxY5nReE2LZ4' |
| 102 |
| 103 result = GetSecrets().recaptcha_private_key |
| 104 if not result: |
| 105 logging.warn('No recaptcha_private_key set. Get one at recaptcha.net.') |
| 106 logging.warn('Store it in Cloud Datastore via the Google Cloud Console.') |
| 107 |
| 108 return result |
| 109 |
| 110 |
OLD | NEW |