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")