From bc16795fa8357033dfaaa224777ae909f6ff5c7f Mon Sep 17 00:00:00 2001 From: Michael Derynck Date: Tue, 11 Oct 2022 14:47:16 -0600 Subject: [PATCH] Allow use of API keys as alternative to account auth token for Twilio credentials --- engine/apps/base/models/live_setting.py | 20 ++++++++--- engine/apps/base/utils.py | 45 +++++++++++++++++++++++-- engine/apps/twilioapp/twilio_client.py | 7 +++- engine/settings/base.py | 2 ++ 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/engine/apps/base/models/live_setting.py b/engine/apps/base/models/live_setting.py index abd5cf1e..129d7e94 100644 --- a/engine/apps/base/models/live_setting.py +++ b/engine/apps/base/models/live_setting.py @@ -35,6 +35,8 @@ class LiveSetting(models.Model): AVAILABLE_NAMES = ( "TWILIO_ACCOUNT_SID", "TWILIO_AUTH_TOKEN", + "TWILIO_API_KEY_SID", + "TWILIO_API_KEY_SECRET", "TWILIO_NUMBER", "TWILIO_VERIFY_SERVICE_SID", "TELEGRAM_TOKEN", @@ -80,14 +82,24 @@ class LiveSetting(models.Model): "after you update them." ), "TWILIO_ACCOUNT_SID": ( - "Twilio username to allow amixr send sms and make phone calls, " + "Twilio account SID/username to allow OnCall send sms and make phone calls, " "" - "more info." + "more info. Required." + ), + "TWILIO_API_KEY_SID": ( + "Twilio API key SID/username to allow OnCall send sms and make phone calls, " + "" + "more info. Either (TWILIO_API_KEY_SID + TWILIO_API_KEY_SECRET) or TWILIO_AUTH_TOKEN is required." + ), + "TWILIO_API_KEY_SECRET": ( + "Twilio API key secret/password to allow OnCall send sms and make phone calls, " + "" + "more info. Either (TWILIO_API_KEY_SID + TWILIO_API_KEY_SECRET) or TWILIO_AUTH_TOKEN is required." ), "TWILIO_AUTH_TOKEN": ( - "Twilio password to allow amixr send sms and make calls, " + "Twilio password to allow OnCall send sms and make calls, " "" - "more info." + "more info. Either (TWILIO_API_KEY_SID + TWILIO_API_KEY_SECRET) or TWILIO_AUTH_TOKEN is required." ), "TWILIO_NUMBER": ( "Number from which you will receive calls and SMS, " diff --git a/engine/apps/base/utils.py b/engine/apps/base/utils.py index 0fe0d8a9..e57a78d7 100644 --- a/engine/apps/base/utils.py +++ b/engine/apps/base/utils.py @@ -50,24 +50,63 @@ class LiveSettingValidator: check_fn = getattr(self, check_fn_name) return check_fn(self.live_setting.value) + @classmethod + def _check_twilio_api_key_sid(cls, twilio_api_key_sid): + if live_settings.TWILIO_AUTH_TOKEN: + return + + try: + Client( + twilio_api_key_sid, live_settings.TWILIO_API_KEY_SECRET, live_settings.TWILIO_ACCOUNT_SID + ).api.applications.list(limit=1) + except Exception as e: + return cls._prettify_twilio_error(e) + + @classmethod + def _check_twilio_api_key_secret(cls, twilio_api_key_secret): + if live_settings.TWILIO_AUTH_TOKEN: + return + + try: + Client( + live_settings.TWILIO_API_KEY_SID, twilio_api_key_secret, live_settings.TWILIO_ACCOUNT_SID + ).api.applications.list(limit=1) + except Exception as e: + return cls._prettify_twilio_error(e) + @classmethod def _check_twilio_account_sid(cls, twilio_account_sid): try: - Client(twilio_account_sid, live_settings.TWILIO_AUTH_TOKEN).api.accounts.list(limit=1) + if live_settings.TWILIO_API_KEY_SID and live_settings.TWILIO_API_KEY_SECRET: + Client( + live_settings.TWILIO_API_KEY_SID, live_settings.TWILIO_API_KEY_SECRET, twilio_account_sid + ).api.applications.list(limit=1) + else: + Client(twilio_account_sid, live_settings.TWILIO_AUTH_TOKEN).api.applications.list(limit=1) except Exception as e: return cls._prettify_twilio_error(e) @classmethod def _check_twilio_auth_token(cls, twilio_auth_token): + if live_settings.TWILIO_API_KEY_SID and live_settings.TWILIO_API_KEY_SECRET: + return + try: - Client(live_settings.TWILIO_ACCOUNT_SID, twilio_auth_token).api.accounts.list(limit=1) + Client(live_settings.TWILIO_ACCOUNT_SID, twilio_auth_token).api.applications.list(limit=1) except Exception as e: return cls._prettify_twilio_error(e) @classmethod def _check_twilio_verify_service_sid(cls, twilio_verify_service_sid): try: - twilio_client = Client(live_settings.TWILIO_ACCOUNT_SID, live_settings.TWILIO_AUTH_TOKEN) + if live_settings.TWILIO_API_KEY_SID and live_settings.TWILIO_API_KEY_SECRET: + twilio_client = Client( + live_settings.TWILIO_API_KEY_SID, + live_settings.TWILIO_API_KEY_SECRET, + live_settings.TWILIO_ACCOUNT_SID, + ) + else: + twilio_client = Client(live_settings.TWILIO_ACCOUNT_SID, live_settings.TWILIO_AUTH_TOKEN) twilio_client.verify.services(twilio_verify_service_sid).rate_limits.list(limit=1) except Exception as e: return cls._prettify_twilio_error(e) diff --git a/engine/apps/twilioapp/twilio_client.py b/engine/apps/twilioapp/twilio_client.py index 007d9e72..75d06403 100644 --- a/engine/apps/twilioapp/twilio_client.py +++ b/engine/apps/twilioapp/twilio_client.py @@ -17,7 +17,12 @@ logger = logging.getLogger(__name__) class TwilioClient: @property def twilio_api_client(self): - return Client(live_settings.TWILIO_ACCOUNT_SID, live_settings.TWILIO_AUTH_TOKEN) + if live_settings.TWILIO_API_KEY_SID and live_settings.TWILIO_API_KEY_SECRET: + return Client( + live_settings.TWILIO_API_KEY_SID, live_settings.TWILIO_API_KEY_SECRET, live_settings.TWILIO_ACCOUNT_SID + ) + else: + return Client(live_settings.TWILIO_ACCOUNT_SID, live_settings.TWILIO_AUTH_TOKEN) @property def twilio_number(self): diff --git a/engine/settings/base.py b/engine/settings/base.py index d9ec9f36..9a5dd09d 100644 --- a/engine/settings/base.py +++ b/engine/settings/base.py @@ -56,6 +56,8 @@ FEATURE_WEB_SCHEDULES_ENABLED = getenv_boolean("FEATURE_WEB_SCHEDULES_ENABLED", GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED = getenv_boolean("GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED", default=True) GRAFANA_CLOUD_NOTIFICATIONS_ENABLED = getenv_boolean("GRAFANA_CLOUD_NOTIFICATIONS_ENABLED", default=True) +TWILIO_API_KEY_SID = os.environ.get("TWILIO_API_KEY_SID") +TWILIO_API_KEY_SECRET = os.environ.get("TWILIO_API_KEY_SECRET") TWILIO_ACCOUNT_SID = os.environ.get("TWILIO_ACCOUNT_SID") TWILIO_AUTH_TOKEN = os.environ.get("TWILIO_AUTH_TOKEN") TWILIO_NUMBER = os.environ.get("TWILIO_NUMBER")