diff --git a/.env.alfajores b/.env.alfajores index efd219523eb..feb8162c6d3 100644 --- a/.env.alfajores +++ b/.env.alfajores @@ -92,7 +92,7 @@ ATTESTATION_BOT_MAX_ATTESTATIONS=32 ATTESTATION_BOT_SKIP_ODIS_SALT=bot ATTESTATION_SERVICE_DOCKER_IMAGE_REPOSITORY="us.gcr.io/celo-testnet/celo-monorepo" -ATTESTATION_SERVICE_DOCKER_IMAGE_TAG="attestation-service-v1.2.0" +ATTESTATION_SERVICE_DOCKER_IMAGE_TAG="attestation-service-v1.3.0" TELEKOM_FROM="+14157389085" SMS_PROVIDERS=twilio,nexmo,telekom diff --git a/.env.mnemonic.alfajores.enc b/.env.mnemonic.alfajores.enc index 2d12c36bdbb..20380532c90 100644 Binary files a/.env.mnemonic.alfajores.enc and b/.env.mnemonic.alfajores.enc differ diff --git a/packages/attestation-service/config/.env.development b/packages/attestation-service/config/.env.development index c25153d6e27..efcce5c0caf 100644 --- a/packages/attestation-service/config/.env.development +++ b/packages/attestation-service/config/.env.development @@ -7,7 +7,7 @@ ATTESTATION_SIGNER_ADDRESS=x # List all SMS providers here. They are tried from first to last, unless # you specify SMS_PROVIDERS_RANDOMIZED=1, in which case they are tried in a random order. -SMS_PROVIDERS=messagebird,twilio,nexmo +SMS_PROVIDERS=twilio # SMS_PROVIDERS_RANDOMIZED=0 # Optional: set a different list or order of providers for a specific country. @@ -43,6 +43,7 @@ NEXMO_UNSUPPORTED_REGIONS=CU,SY,KP,IR,SD # Twilio parameters (fill in values for 'x') TWILIO_ACCOUNT_SID=x TWILIO_MESSAGING_SERVICE_SID=x +TWILIO_VERIFY_SERVICE_SID=x TWILIO_AUTH_TOKEN=x TWILIO_UNSUPPORTED_REGIONS=CU,SY,KP,IR,SD diff --git a/packages/attestation-service/migrations/20210625231054-attestation-v7.js b/packages/attestation-service/migrations/20210625231054-attestation-v7.js new file mode 100644 index 00000000000..e777c76c24f --- /dev/null +++ b/packages/attestation-service/migrations/20210625231054-attestation-v7.js @@ -0,0 +1,32 @@ +'use strict' +module.exports = { + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + + try { + await queryInterface.addColumn('Attestations', 'appSignature', { + type: Sequelize.STRING, + allowNull: true, + }) + await queryInterface.addColumn('Attestations', 'language', { + type: Sequelize.STRING, + allowNull: true, + }) + + await transaction.commit() + } catch (error) { + await transaction.rollback() + throw error + } + }, + down: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.removeColumn('Attestations', 'appSignature') + await queryInterface.removeColumn('Attestations', 'language') + } catch (error) { + await transaction.rollback() + throw error + } + }, +} diff --git a/packages/attestation-service/package.json b/packages/attestation-service/package.json index 4f4035f6828..701e088b4c3 100644 --- a/packages/attestation-service/package.json +++ b/packages/attestation-service/package.json @@ -1,6 +1,6 @@ { "name": "@celo/attestation-service", - "version": "1.2.2", + "version": "1.3.0", "description": "Issues attestation messages for Celo's identity protocol", "main": "./lib/index.js", "types": "./lib/index.d.ts", diff --git a/packages/attestation-service/src/models/attestation.ts b/packages/attestation-service/src/models/attestation.ts index da197085b6b..d5cefade928 100644 --- a/packages/attestation-service/src/models/attestation.ts +++ b/packages/attestation-service/src/models/attestation.ts @@ -24,6 +24,8 @@ export interface AttestationModel extends Model { recordError: (error: string) => void failure: () => boolean currentError: () => string | undefined + appSignature: string | undefined + language: string | undefined } export interface AttestationKey { @@ -64,6 +66,8 @@ export default (sequelize: Sequelize) => { errors: DataTypes.STRING, createdAt: DataTypes.DATE, completedAt: DataTypes.DATE, + appSignature: DataTypes.STRING, + language: DataTypes.STRING, }) as AttestationStatic model.prototype.key = function (): AttestationKey { diff --git a/packages/attestation-service/src/requestHandlers/attestation.ts b/packages/attestation-service/src/requestHandlers/attestation.ts index 1d6b21f0de2..af50cbec053 100644 --- a/packages/attestation-service/src/requestHandlers/attestation.ts +++ b/packages/attestation-service/src/requestHandlers/attestation.ts @@ -152,35 +152,41 @@ class AttestationRequestHandler { // Main process for handling an attestation. async doAttestation() { Counters.attestationRequestsTotal.inc() + if ( + !this.attestationRequest.securityCodePrefix || + this.attestationRequest.securityCodePrefix.length !== 1 + ) { + throw new ErrorWithResponse('Invalid securityCodePrefix', 422) + } + let attestation = await this.findOrValidateRequest() if (attestation && attestation.message) { // Re-request existing attestation. In this case, security code prefix is ignored (the message sent is the same as before) - attestation = await rerequestAttestation(this.key, this.logger, this.sequelizeLogger) + attestation = await rerequestAttestation( + this.key, + this.attestationRequest.smsRetrieverAppSig, + this.attestationRequest.language, + this.attestationRequest.securityCodePrefix, + this.logger, + this.sequelizeLogger + ) } else { // New attestation: create new attestation code, new delivery. const attestationCode = await this.signAttestation() await this.validateAttestationCode(attestationCode) + // This attestation code is stored in the attestation object + // and will be returned to the user with the get_attestation call const attestationCodeDeeplink = `celo://wallet/v/${toBase64(attestationCode)}` - // Determine if we're sending a security code, or the full deep link. let messageBase, securityCode - if (this.attestationRequest.securityCodePrefix) { - if (this.attestationRequest.securityCodePrefix.length !== 1) { - throw new ErrorWithResponse('Invalid securityCodePrefix', 422) - } - // Client is requesting a security code SMS. Generate a challenge and just store the deeplink. - securityCode = randomBytes(7) - .map((x) => x % 10) - .join('') - messageBase = `${getSecurityCodeText(this.attestationRequest.language)}: ${ - this.attestationRequest.securityCodePrefix - }${securityCode}` - } else { - // Client is requesting direct SMS with the deeplink. - messageBase = attestationCodeDeeplink - } + // Generate a security code to be sent over SMS + securityCode = randomBytes(7) + .map((x) => x % 10) + .join('') + securityCode = `${this.attestationRequest.securityCodePrefix}${securityCode}` + messageBase = `${getSecurityCodeText(this.attestationRequest.language)}: ${securityCode}` let textMessage @@ -200,6 +206,8 @@ class AttestationRequestHandler { textMessage, securityCode, attestationCodeDeeplink, + this.attestationRequest.smsRetrieverAppSig, + this.attestationRequest.language, this.logger, this.sequelizeLogger ) diff --git a/packages/attestation-service/src/requestHandlers/get_attestation.ts b/packages/attestation-service/src/requestHandlers/get_attestation.ts index 8bc586d1e3e..60a292230b3 100644 --- a/packages/attestation-service/src/requestHandlers/get_attestation.ts +++ b/packages/attestation-service/src/requestHandlers/get_attestation.ts @@ -77,7 +77,12 @@ class GetAttestationRequestHandler { } // Security code is supplied. Check it's correct. - if (attestation.securityCode === this.getRequest.securityCode) { + // Check with both methods (can remove second method after 1.3.0) + if ( + attestation.securityCode && + (attestation.securityCode.slice(1) === this.getRequest.securityCode || + attestation.securityCode === this.getRequest.securityCode) + ) { callback(attestation, attestation.attestationCode) await transaction.commit() return diff --git a/packages/attestation-service/src/requestHandlers/status.ts b/packages/attestation-service/src/requestHandlers/status.ts index b4adcfbee1e..8a906ad24f2 100644 --- a/packages/attestation-service/src/requestHandlers/status.ts +++ b/packages/attestation-service/src/requestHandlers/status.ts @@ -53,6 +53,7 @@ export async function handleStatusRequest( 10 ), maxRerequestMins: parseInt(fetchEnvOrDefault('MAX_REREQUEST_MINS', '55'), 10), + twilioVerifySidProvided: !!fetchEnvOrDefault('TWILIO_VERIFY_SERVICE_SID', ''), }) ) .status(200) diff --git a/packages/attestation-service/src/requestHandlers/test_attestation.ts b/packages/attestation-service/src/requestHandlers/test_attestation.ts index feddae91241..c9d45a1d7ed 100644 --- a/packages/attestation-service/src/requestHandlers/test_attestation.ts +++ b/packages/attestation-service/src/requestHandlers/test_attestation.ts @@ -54,8 +54,10 @@ export async function handleTestAttestationRequest( key, testRequest.phoneNumber, testRequest.message, - null, + '12345678', testRequest.message, + undefined, + undefined, logger, sequelizeLogger, testRequest.provider diff --git a/packages/attestation-service/src/sms/index.ts b/packages/attestation-service/src/sms/index.ts index e9c10c642db..aa909713256 100644 --- a/packages/attestation-service/src/sms/index.ts +++ b/packages/attestation-service/src/sms/index.ts @@ -203,6 +203,8 @@ export async function startSendSms( messageToSend: string, securityCode: string | null = null, attestationCode: string | null = null, + appSignature: string | undefined, + language: string | undefined, logger: Logger, sequelizeLogger: SequelizeLogger, onlyUseProvider: string | null = null @@ -243,6 +245,8 @@ export async function startSendSms( ongoingDeliveryId: null, securityCode, securityCodeAttempt: 0, + appSignature, + language, }, transaction ) @@ -285,6 +289,9 @@ export async function startSendSms( // immediately if there are sufficient attempts remaining. export async function rerequestAttestation( key: AttestationKey, + appSignature: string | undefined, + language: string | undefined, + securityCodePrefix: string, logger: Logger, sequelizeLogger: SequelizeLogger ): Promise { @@ -301,6 +308,18 @@ export async function rerequestAttestation( if (!attestation) { throw new Error('Cannot retrieve attestation') } + // For backward compatibility + // Can be removed after 1.3.0 + if (!attestation.appSignature) { + attestation.appSignature = appSignature + } + if (!attestation.language) { + attestation.language = language + } + // Old security code approach did not store the prefix + if (attestation.securityCode?.length === 7) { + attestation.securityCode = `${securityCodePrefix}${attestation.securityCode}` + } if (attestation.completedAt) { const completedAgo = Date.now() - attestation.completedAt!.getTime() diff --git a/packages/attestation-service/src/sms/twilio.ts b/packages/attestation-service/src/sms/twilio.ts index 0b5b6b578cd..d4e1cced30e 100644 --- a/packages/attestation-service/src/sms/twilio.ts +++ b/packages/attestation-service/src/sms/twilio.ts @@ -2,7 +2,7 @@ import bodyParser from 'body-parser' import Logger from 'bunyan' import express from 'express' import twilio, { Twilio } from 'twilio' -import { fetchEnv } from '../env' +import { fetchEnv, fetchEnvOrDefault } from '../env' import { AttestationModel, AttestationStatus } from '../models/attestation' import { readUnsupportedRegionsFromEnv, SmsProvider, SmsProviderType } from './base' import { receivedDeliveryReport } from './index' @@ -12,6 +12,7 @@ export class TwilioSmsProvider extends SmsProvider { return new TwilioSmsProvider( fetchEnv('TWILIO_ACCOUNT_SID'), fetchEnv('TWILIO_MESSAGING_SERVICE_SID'), + fetchEnvOrDefault('TWILIO_VERIFY_SERVICE_SID', ''), fetchEnv('TWILIO_AUTH_TOKEN'), readUnsupportedRegionsFromEnv('TWILIO_UNSUPPORTED_REGIONS', 'TWILIO_BLACKLIST') ) @@ -19,18 +20,60 @@ export class TwilioSmsProvider extends SmsProvider { client: Twilio messagingServiceSid: string + verifyServiceSid: string type = SmsProviderType.TWILIO deliveryStatusURL: string | undefined + // https://www.twilio.com/docs/verify/api/verification#start-new-verification + twilioSupportedLocales = [ + 'af', + 'ar', + 'ca', + 'cs', + 'da', + 'de', + 'el', + 'en', + 'en-gb', + 'es', + 'fi', + 'fr', + 'he', + 'hi', + 'hr', + 'hu', + 'id', + 'it', + 'ja', + 'ko', + 'ms', + 'nb', + 'nl', + 'pl', + 'pt', + 'pr-br', + 'ro', + 'ru', + 'sv', + 'th', + 'tl', + 'tr', + 'vi', + 'zh', + 'zh-cn', + 'zh-hk', + ] constructor( twilioSid: string, messagingServiceSid: string, + verifyServiceSid: string, twilioAuthToken: string, unsupportedRegionCodes: string[] ) { super() this.client = twilio(twilioSid, twilioAuthToken) this.messagingServiceSid = messagingServiceSid + this.verifyServiceSid = verifyServiceSid this.unsupportedRegionCodes = unsupportedRegionCodes } @@ -76,15 +119,76 @@ export class TwilioSmsProvider extends SmsProvider { } catch (error) { throw new Error(`Twilio Messaging Service could not be fetched: ${error}`) } + if (this.verifyServiceSid) { + try { + await this.client.verify.services + .get(this.verifyServiceSid) + .fetch() + .then((service) => { + if (!service.customCodeEnabled) { + // Make sure that custom code is enabled + throw new Error( + 'TWILIO_VERIFY_SERVICE_SID is specified, but customCode is not enabled. Please contact Twilio support to enable it.' + ) + } + }) + } catch (error) { + throw new Error(`Twilio Verify Service could not be fetched: ${error}`) + } + } } async sendSms(attestation: AttestationModel) { - const m = await this.client.messages.create({ - body: attestation.message, - to: attestation.phoneNumber, - from: this.messagingServiceSid, - statusCallback: this.deliveryStatusURL, - }) - return m.sid + // Prefer Verify API if Verify Service is present + if (this.verifyServiceSid) { + const requestParams: any = { + to: attestation.phoneNumber, + channel: 'sms', + customCode: attestation.securityCode, + } + + // This param tells Twilio to add the <#> prefix and app hash postfix + if (attestation.appSignature) { + requestParams.appHash = attestation.appSignature + } + // Normalize to locales that Twilio supports + // If locale is not supported, Twilio API will throw an error + if (attestation.language) { + const locale = attestation.language.toLocaleLowerCase() + if (['es-419', 'es-us', 'es-la'].includes(locale)) { + attestation.language = 'es' + } + if (this.twilioSupportedLocales.includes(locale)) { + requestParams.locale = locale + } + } + try { + const m = await this.client.verify + .services(this.verifyServiceSid) + .verifications.create(requestParams) + return m.sid + } catch (e) { + // Verify landlines using voice + if (e.message.includes('SMS is not supported by landline phone number')) { + requestParams.appHash = undefined + requestParams.channel = 'call' + const m = await this.client.verify + .services(this.verifyServiceSid) + .verifications.create(requestParams) + return m.sid + } else { + throw e + } + } + } else { + // Send using the message service + const m = await this.client.messages.create({ + body: attestation.message, + to: attestation.phoneNumber, + from: this.messagingServiceSid, + statusCallback: this.deliveryStatusURL, + }) + return m.sid + } } } diff --git a/packages/azure/scripts/provider-init.sh b/packages/azure/scripts/provider-init.sh index 56da9c38d89..bd0332fd109 100644 --- a/packages/azure/scripts/provider-init.sh +++ b/packages/azure/scripts/provider-init.sh @@ -27,6 +27,7 @@ PROXY_URL="enode://${proxyPublicKey}@${proxyInternalIpAddress}:30503;enode://${p SMS_PROVIDERS=twilio ATTESTER_TWILIO_ACCOUNT_SID=${attesterTwilioAccountSID} ATTESTER_TWILIO_MESSAGE_SERVICE_SID=${attesterTwilioMessageServiceSID} +ATTESTER_TWILIO_VERIFY_SERVICE_SID=${attesterTwilioVerifyServiceSID} ATTESTER_DB_USERNAME="${attesterPostgreSQLUsername}@${attesterDBName}" ATTESTER_DB_HOSTNAME="${attesterDBName}.postgres.database.azure.com" EOF diff --git a/packages/celotool/src/lib/attestation-service.ts b/packages/celotool/src/lib/attestation-service.ts index c181ee294e4..3ff3385b874 100644 --- a/packages/celotool/src/lib/attestation-service.ts +++ b/packages/celotool/src/lib/attestation-service.ts @@ -49,6 +49,7 @@ async function helmParameters(celoEnv: string) { `--set attestation_service.twilio.accountSid="${fetchEnv(envVar.TWILIO_ACCOUNT_SID)}"`, `--set attestation_service.twilio.authToken="${fetchEnv(envVar.TWILIO_ACCOUNT_AUTH_TOKEN)}"`, `--set attestation_service.twilio.addressSid="${fetchEnv(envVar.TWILIO_ADDRESS_SID)}"`, + `--set attestation_service.twilio.verifySid="${fetchEnv(envVar.TWILIO_VERIFY_SERVICE_SID)}"`, `--set attestation_service.nexmo.apiKey="${fetchEnv(envVar.NEXMO_KEY)}"`, `--set attestation_service.nexmo.apiSecret="${fetchEnv(envVar.NEXMO_SECRET)}"`, `--set attestation_service.telekom.apiKey="${fetchEnv(envVar.TELEKOM_API_KEY)}"`, diff --git a/packages/celotool/src/lib/env-utils.ts b/packages/celotool/src/lib/env-utils.ts index bc7afdf9793..e76adef2ea5 100644 --- a/packages/celotool/src/lib/env-utils.ts +++ b/packages/celotool/src/lib/env-utils.ts @@ -148,6 +148,7 @@ export enum envVar { TWILIO_ACCOUNT_AUTH_TOKEN = 'TWILIO_ACCOUNT_AUTH_TOKEN', TWILIO_ACCOUNT_SID = 'TWILIO_ACCOUNT_SID', TWILIO_ADDRESS_SID = 'TWILIO_ADDRESS_SID', + TWILIO_VERIFY_SERVICE_SID = `TWILIO_VERIFY_SERVICE_SID`, TX_NODES = 'TX_NODES', TX_NODES_PRIVATE_ROLLING_UPDATE_PARTITION = 'TX_NODES_PRIVATE_ROLLING_UPDATE_PARTITION', TX_NODES_ROLLING_UPDATE_PARTITION = 'TX_NODES_ROLLING_UPDATE_PARTITION', diff --git a/packages/docs/validator-guide/attestation-service.md b/packages/docs/validator-guide/attestation-service.md index 0860b413036..c6607cc6121 100644 --- a/packages/docs/validator-guide/attestation-service.md +++ b/packages/docs/validator-guide/attestation-service.md @@ -63,6 +63,26 @@ To actually be able to send SMS, you need to create a messaging service under [P Now that you have provisioned your messaging service, you need to buy at least 1 phone number to send SMS from. You can do so under the `Numbers` option of the messaging service page. It is strongly recommended that you purchase at least a US (`+1`) number which seem to provide high delivery success rates. If you purchase numbers in other locales, Twilio will intelligently select the best number to send each SMS. +#### Verify Service (post v1.3.0) + +We're in the process of transitioning to [Twilio's Verify Service](https://www.twilio.com/verify) which will automatically manage a set of phone numbers for global reach. Create a Verify Service in the Twilio Portal by navigating to [Verify](https://www.twilio.com/console/verify/services) and click `+` to create a new service. It's important to provide `Celo` as the service friendly name, since this will show up in the text message content. + +1. Set the code length to `8 digits`. +2. Enter `sell-oh` in the `TTS SERVICE NAME`. +3. Enable `SMS`, `CALL`, and `EMAIL` delivery channels. + +After you create the Verify Service, you **[must create a support ticket](https://www.twilio.com/console/support/tickets/create)** to enable the `custom code` feature. Provide Twilio support your new Verify SID and request enabling the `custom code` feature. Please monitor for a response and respond to any follow up questions. + +Support ticket request template + +> Hello, I'd like to enable custom codes for our Verify API with SID {YOUR_VERIFY_SID}. I understand that we will be charged on each attempted user verification. + +After Twilio enables custom codes, you'll see the following property in the Twilio dashboard when viewing your Verify Service: + +![Custom Code Property](https://storage.googleapis.com/celo-website/docs/custom-code.png) + +Once you have confirmation that custom codes are enabled on your Twilio account, you can provide the resulting `SID` in the `TWILIO_VERIFY_SERVICE_SID` configuration variable and start the service. In the future, we'll likely switch entirely to the Verify Service and deprecate the Messaging Service, but for now it's important to specify both. + ### Nexmo After signing up for [Nexmo](https://dashboard.nexmo.com/sign-up), click the balance in the top-left to go to [Billing and Payments](https://dashboard.nexmo.com/billing-and-payments), where you can add funds. It is strongly recommended that you use a credit or debit card (as opposed to other forms of payment) as you will then be able to enable `Auto reload`. You should also enable `Low balance alerts`. Both of these will help avoid failing to deliver SMS when your funds are exhausted. It appears that these options may not be immediately available for all new accounts due to fraud checks: try sending a few SMS, checking back after a few days, or raising a support ticket. @@ -186,6 +206,7 @@ Twilio configuration options: | ------------------------------ | --------------------------------------------------------------- | | `TWILIO_ACCOUNT_SID` | The Twilio account ID | | `TWILIO_MESSAGING_SERVICE_SID` | The Twilio Message Service ID. Starts with `MG` | +| `TWILIO_VERIFY_SERVICE_SID` | The Twilio Verify Service ID. Starts with `VA` | | `TWILIO_AUTH_TOKEN` | The API authentication token | | `TWILIO_UNSUPPORTED_REGIONS` | Optional. A comma-separated list of country codes to not serve, recommended value `CU,SY,KP,IR,SD` | diff --git a/packages/helm-charts/attestation-service/templates/attestation.secret.yaml b/packages/helm-charts/attestation-service/templates/attestation.secret.yaml index d6241b3c15c..6bc412007f2 100644 --- a/packages/helm-charts/attestation-service/templates/attestation.secret.yaml +++ b/packages/helm-charts/attestation-service/templates/attestation.secret.yaml @@ -15,4 +15,5 @@ data: TWILIO_ACCOUNT_SID: {{ .Values.attestation_service.twilio.accountSid | b64enc }} TWILIO_AUTH_TOKEN: {{ .Values.attestation_service.twilio.authToken | b64enc }} TWILIO_MESSAGING_SERVICE_SID: {{ .Values.attestation_service.twilio.addressSid | b64enc }} + TWILIO_VERIFY_SERVICE_SID: {{ .Values.attestation_service.twilio.verifySid | b64enc }} TELEKOM_API_KEY: {{ .Values.attestation_service.telekom.apiKey | b64enc }} diff --git a/packages/helm-charts/attestation-service/templates/attestation.statefulset.yaml b/packages/helm-charts/attestation-service/templates/attestation.statefulset.yaml index 06a24607dd7..aa6c440bff2 100644 --- a/packages/helm-charts/attestation-service/templates/attestation.statefulset.yaml +++ b/packages/helm-charts/attestation-service/templates/attestation.statefulset.yaml @@ -130,9 +130,11 @@ spec: args: - "-c" - | + RID=`cat /root/.celo/replica_id` + export DATABASE_URL=$DATABASE_URL_PREFIX$DATABASE_NAME + yarn sequelize db:create $DATABASE_NAME yarn db:migrate sleep 5 - RID=`cat /root/.celo/replica_id` NEXMO_APPLICATIONS={{- range $index, $application := .Values.attestation_service.nexmo.applications -}}{{ $application }},{{- end }} NEXMO_APPLICATION=`echo -n $NEXMO_APPLICATIONS | cut -d ',' -f $((RID + 1))` ATTESTATION_SIGNER_ADDRESS=`cat /root/.celo/attestationSignerAddress` CELO_VALIDATOR_ADDRESS=`cat /root/.celo/address` exec yarn start ports: @@ -143,8 +145,12 @@ spec: cpu: 50m memory: 150Mi env: - - name: DATABASE_URL - value: postgres://postgres:password@{{ .Release.Namespace }}-attestation-service-postgresql:5432/AttestationService + - name: DATABASE_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: DATABASE_URL_PREFIX + value: postgres://postgres:password@{{ .Release.Namespace }}-attestation-service-postgresql:5432/ - name: NODE_ENV value: production - name: CELO_PROVIDER @@ -182,6 +188,11 @@ spec: secretKeyRef: name: {{ .Release.Name }} key: TWILIO_MESSAGING_SERVICE_SID + - name: TWILIO_VERIFY_SERVICE_SID + valueFrom: + secretKeyRef: + name: {{ .Release.Name }} + key: TWILIO_VERIFY_SERVICE_SID - name: TWILIO_AUTH_TOKEN valueFrom: secretKeyRef: diff --git a/packages/metadata-crawler/src/crawler.ts b/packages/metadata-crawler/src/crawler.ts index 3bd791fae37..d4489be8d38 100644 --- a/packages/metadata-crawler/src/crawler.ts +++ b/packages/metadata-crawler/src/crawler.ts @@ -193,6 +193,7 @@ async function processAttestationServiceStatusForValidator( smsProvidersRandomized, maxDeliveryAttempts, maxRerequestMins, + twilioVerifySidProvided, } = status const isElected = electedValidators.has(validator.address) dataLogger.info( @@ -214,6 +215,7 @@ async function processAttestationServiceStatusForValidator( smsProvidersRandomized, maxDeliveryAttempts, maxRerequestMins, + twilioVerifySidProvided, }, 'checked_attestation_service_status' ) diff --git a/packages/sdk/contractkit/src/wrappers/Attestations.ts b/packages/sdk/contractkit/src/wrappers/Attestations.ts index f008dded32d..397a529c6b4 100644 --- a/packages/sdk/contractkit/src/wrappers/Attestations.ts +++ b/packages/sdk/contractkit/src/wrappers/Attestations.ts @@ -708,6 +708,7 @@ export class AttestationsWrapper extends BaseWrapper { smsProvidersRandomized: null, maxDeliveryAttempts: null, maxRerequestMins: null, + twilioVerifySidProvided: null, } if (!hasAttestationSigner) { @@ -767,6 +768,7 @@ export class AttestationsWrapper extends BaseWrapper { ret.smsProvidersRandomized = statusResponseBody.smsProvidersRandomized ret.maxDeliveryAttempts = statusResponseBody.maxDeliveryAttempts ret.maxRerequestMins = statusResponseBody.maxRerequestMins + ret.twilioVerifySidProvided = statusResponseBody.twilioVerifySidProvided // Healthcheck was added in 1.0.1, same time version started being reported. if (statusResponseBody.version) { @@ -853,4 +855,5 @@ export interface AttestationServiceStatusResponse { smsProvidersRandomized: boolean | null maxDeliveryAttempts: number | null maxRerequestMins: number | null + twilioVerifySidProvided: boolean | null } diff --git a/packages/sdk/utils/src/io.ts b/packages/sdk/utils/src/io.ts index ea5e6ed349d..5b4bf3ebd8e 100644 --- a/packages/sdk/utils/src/io.ts +++ b/packages/sdk/utils/src/io.ts @@ -90,6 +90,7 @@ export const AttestationServiceStatusResponseType = t.type({ smsProvidersRandomized: t.boolean, maxDeliveryAttempts: t.number, maxRerequestMins: t.number, + twilioVerifySidProvided: t.boolean, }) export const AttestationServiceTestRequestType = t.type({ diff --git a/packages/terraform-modules-public/aws/examples/mainnet/main.tf b/packages/terraform-modules-public/aws/examples/mainnet/main.tf index 6a87320beeb..3ebd6d3442a 100644 --- a/packages/terraform-modules-public/aws/examples/mainnet/main.tf +++ b/packages/terraform-modules-public/aws/examples/mainnet/main.tf @@ -28,6 +28,7 @@ module "celo_cluster" { celo_image_attestation = var.celo_image_attestation ethstats_host = var.ethstats_host twilio_messaging_service_sid = var.twilio_messaging_service_sid + twilio_verify_service_sid = var.twilio_verify_service_sid twilio_account_sid = var.twilio_account_sid twilio_unsupported_regions = var.twilio_unsupported_regions twilio_auth_token = var.twilio_auth_token diff --git a/packages/terraform-modules-public/aws/examples/mainnet/variables.tf b/packages/terraform-modules-public/aws/examples/mainnet/variables.tf index 9829705766c..4c83e420ca0 100644 --- a/packages/terraform-modules-public/aws/examples/mainnet/variables.tf +++ b/packages/terraform-modules-public/aws/examples/mainnet/variables.tf @@ -169,6 +169,10 @@ variable twilio_messaging_service_sid { type = string } +variable twilio_verify_service_sid { + type = string +} + variable twilio_account_sid { type = string } diff --git a/packages/terraform-modules-public/aws/examples/testnet/main.tf b/packages/terraform-modules-public/aws/examples/testnet/main.tf index 6a87320beeb..3ebd6d3442a 100644 --- a/packages/terraform-modules-public/aws/examples/testnet/main.tf +++ b/packages/terraform-modules-public/aws/examples/testnet/main.tf @@ -28,6 +28,7 @@ module "celo_cluster" { celo_image_attestation = var.celo_image_attestation ethstats_host = var.ethstats_host twilio_messaging_service_sid = var.twilio_messaging_service_sid + twilio_verify_service_sid = var.twilio_verify_service_sid twilio_account_sid = var.twilio_account_sid twilio_unsupported_regions = var.twilio_unsupported_regions twilio_auth_token = var.twilio_auth_token diff --git a/packages/terraform-modules-public/aws/examples/testnet/variables.tf b/packages/terraform-modules-public/aws/examples/testnet/variables.tf index aa04487f545..c40a387b605 100644 --- a/packages/terraform-modules-public/aws/examples/testnet/variables.tf +++ b/packages/terraform-modules-public/aws/examples/testnet/variables.tf @@ -169,6 +169,10 @@ variable twilio_messaging_service_sid { type = string } +variable twilio_verify_service_sid { + type = string +} + variable twilio_account_sid { type = string } diff --git a/packages/terraform-modules-public/aws/testnet/main.tf b/packages/terraform-modules-public/aws/testnet/main.tf index e76a5fae7df..1784231e90f 100644 --- a/packages/terraform-modules-public/aws/testnet/main.tf +++ b/packages/terraform-modules-public/aws/testnet/main.tf @@ -184,6 +184,7 @@ module "celo_attestation_service_az1" { celo_image_attestation = var.celo_image_attestation database_url = local.attestation_db_url twilio_messaging_service_sid = var.twilio_messaging_service_sid + twilio_verify_service_sid = var.twilio_verify_service_sid twilio_account_sid = var.twilio_account_sid twilio_unsupported_regions = var.twilio_unsupported_regions twilio_auth_token = var.twilio_auth_token @@ -210,6 +211,7 @@ module "celo_attestation_service_az2" { celo_image_attestation = var.celo_image_attestation database_url = local.attestation_db_url twilio_messaging_service_sid = var.twilio_messaging_service_sid + twilio_verify_service_sid = var.twilio_verify_service_sid twilio_account_sid = var.twilio_account_sid twilio_unsupported_regions = var.twilio_unsupported_regions twilio_auth_token = var.twilio_auth_token diff --git a/packages/terraform-modules-public/aws/testnet/modules/attestation-service/main.tf b/packages/terraform-modules-public/aws/testnet/modules/attestation-service/main.tf index 7dd24cc6a39..7d765c1e966 100644 --- a/packages/terraform-modules-public/aws/testnet/modules/attestation-service/main.tf +++ b/packages/terraform-modules-public/aws/testnet/modules/attestation-service/main.tf @@ -30,6 +30,7 @@ resource "aws_instance" "attestation_service" { attestation_signer_private_key_password = each.value.attestation_signer_private_key_password database_url = var.database_url twilio_messaging_service_sid = var.twilio_messaging_service_sid + twilio_verify_service_sid = var.twilio_verify_service_sid twilio_account_sid = var.twilio_account_sid twilio_unsupported_regions = var.twilio_unsupported_regions twilio_auth_token = var.twilio_auth_token diff --git a/packages/terraform-modules-public/aws/testnet/modules/attestation-service/variables.tf b/packages/terraform-modules-public/aws/testnet/modules/attestation-service/variables.tf index 0f2d240dad7..7b01b1badbd 100644 --- a/packages/terraform-modules-public/aws/testnet/modules/attestation-service/variables.tf +++ b/packages/terraform-modules-public/aws/testnet/modules/attestation-service/variables.tf @@ -44,6 +44,10 @@ variable twilio_messaging_service_sid { type = string } +variable twilio_verify_service_sid { + type = string +} + variable twilio_account_sid { type = string } diff --git a/packages/terraform-modules-public/aws/testnet/modules/startup-scripts/run-attestation-service.sh b/packages/terraform-modules-public/aws/testnet/modules/startup-scripts/run-attestation-service.sh index f5e5251633f..b3a56b162e4 100644 --- a/packages/terraform-modules-public/aws/testnet/modules/startup-scripts/run-attestation-service.sh +++ b/packages/terraform-modules-public/aws/testnet/modules/startup-scripts/run-attestation-service.sh @@ -45,6 +45,7 @@ echo 'NEXMO_UNSUPPORTED_REGIONS=${nexmo_unsupported_regions}' >> $CONFIG_FILE_PA echo 'TWILIO_ACCOUNT_SID=${twilio_account_sid}' >> $CONFIG_FILE_PATH echo 'TWILIO_MESSAGING_SERVICE_SID=${twilio_messaging_service_sid}' >> $CONFIG_FILE_PATH +echo 'TWILIO_VERIFY_SERVICE_SID=${twilio_verify_service_sid}' >> $CONFIG_FILE_PATH echo 'TWILIO_AUTH_TOKEN=${twilio_auth_token}' >> $CONFIG_FILE_PATH echo 'TWILIO_UNSUPPORTED_REGIONS=${twilio_unsupported_regions}' >> $CONFIG_FILE_PATH diff --git a/packages/terraform-modules-public/aws/testnet/variables.tf b/packages/terraform-modules-public/aws/testnet/variables.tf index 8fa1e4eef4b..6d4150e1b3f 100644 --- a/packages/terraform-modules-public/aws/testnet/variables.tf +++ b/packages/terraform-modules-public/aws/testnet/variables.tf @@ -95,6 +95,10 @@ variable twilio_messaging_service_sid { type = string } +variable twilio_verify_service_sid { + type = string +} + variable twilio_account_sid { type = string } diff --git a/packages/terraform-modules-public/gcp/celo-infra/main.tf b/packages/terraform-modules-public/gcp/celo-infra/main.tf index 7a639290d5c..f97db443e9b 100644 --- a/packages/terraform-modules-public/gcp/celo-infra/main.tf +++ b/packages/terraform-modules-public/gcp/celo-infra/main.tf @@ -263,6 +263,7 @@ module "attestation-service" { nexmo_unsupported_regions = var.attestation_service_nexmo_unsupported_regions twilio_account_sid = var.attestation_service_twilio_account_sid twilio_messaging_service_sid = var.attestation_service_twilio_messaging_service_sid + twilio_verify_service_sid = var.attestation_service_twilio_verify_service_sid twilio_auth_token = var.attestation_service_twilio_auth_token twilio_blacklist = var.attestation_service_twilio_blacklist twilio_unsupported_regions = var.attestation_service_twilio_unsupported_regions diff --git a/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/main.tf b/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/main.tf index 8b71c876399..21f07da7843 100644 --- a/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/main.tf +++ b/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/main.tf @@ -78,6 +78,7 @@ resource "google_compute_instance" "attestation_service" { nexmo_unsupported_regions : var.nexmo_unsupported_regions, twilio_account_sid : var.twilio_account_sid, twilio_messaging_service_sid : var.twilio_messaging_service_sid, + twilio_verify_service_sid : var.twilio_verify_service_sid, twilio_auth_token : var.twilio_auth_token, twilio_blacklist : var.twilio_blacklist, twilio_unsupported_regions : var.twilio_unsupported_regions, diff --git a/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/startup.sh b/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/startup.sh index 3e518b1662a..3f03124f275 100644 --- a/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/startup.sh +++ b/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/startup.sh @@ -206,6 +206,7 @@ NEXMO_BLACKLIST='${nexmo_blacklist}' NEXMO_UNSUPPORTED_REGIONS='${nexmo_unsupported_regions}' TWILIO_ACCOUNT_SID='${twilio_account_sid}' TWILIO_MESSAGING_SERVICE_SID='${twilio_messaging_service_sid}' +TWILIO_VERIFY_SERVICE_SID='${twilio_verify_service_sid}' TWILIO_AUTH_TOKEN='${twilio_auth_token}' TWILIO_BLACKLIST='${twilio_blacklist}' TWILIO_UNSUPPORTED_REGIONS='${twilio_unsupported_regions}' @@ -256,6 +257,7 @@ save_variable "$NEXMO_SECRET" "$DATA_DIR/nexmoSecret" save_variable "$NEXMO_BLACKLIST" "$DATA_DIR/nexmoBlacklist" save_variable "$TWILIO_ACCOUNT_SID" "$DATA_DIR/twilioAccountSid" save_variable "$TWILIO_MESSAGING_SERVICE_SID" "$DATA_DIR/twilioMessagingServiceSid" +save_variable "$TWILIO_VERIFY_SERVICE_SID" "$DATA_DIR/twilioVerifyServiceSid" save_variable "$TWILIO_AUTH_TOKEN" "$DATA_DIR/twilioAuthToken" save_variable "$TWILIO_BLACKLIST" "$DATA_DIR/twilioBlacklist" save_variable "$TWILIO_UNSUPPORTED_REGIONS" "$DATA_DIR/twilioUnsupportedRegions" @@ -291,6 +293,7 @@ ExecStart=/usr/bin/docker run \\ -e NEXMO_UNSUPPORTED_REGIONS="$NEXMO_UNSUPPORTED_REGIONS" \\ -e TWILIO_ACCOUNT_SID="$TWILIO_ACCOUNT_SID" \\ -e TWILIO_MESSAGING_SERVICE_SID="$TWILIO_MESSAGING_SERVICE_SID" \\ + -e TWILIO_VERIFY_SERVICE_SID="$TWILIO_VERIFY_SERVICE_SID" \\ -e TWILIO_AUTH_TOKEN="$TWILIO_AUTH_TOKEN" \\ -e TWILIO_BLACKLIST="$TWILIO_BLACKLIST" \\ -e TWILIO_UNSUPPORTED_REGIONS="$TWILIO_UNSUPPORTED_REGIONS" \\ diff --git a/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/variables.tf b/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/variables.tf index 1f57aea1aa6..db03e5aab62 100644 --- a/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/variables.tf +++ b/packages/terraform-modules-public/gcp/celo-infra/modules/attestation-service/variables.tf @@ -106,7 +106,12 @@ variable twilio_account_sid { variable twilio_messaging_service_sid { type = string - description = "Twilio account messagin service SID (check twilio documentation)" + description = "Twilio account messaging service SID (check twilio documentation)" +} + +variable twilio_verify_service_sid { + type = string + description = "Twilio account verify service SID (check twilio documentation)" } variable twilio_auth_token { diff --git a/packages/terraform-modules-public/gcp/celo-infra/variables.tf b/packages/terraform-modules-public/gcp/celo-infra/variables.tf index e7cc5c11c4d..30e300709d0 100644 --- a/packages/terraform-modules-public/gcp/celo-infra/variables.tf +++ b/packages/terraform-modules-public/gcp/celo-infra/variables.tf @@ -234,7 +234,13 @@ variable attestation_service_twilio_account_sid { variable attestation_service_twilio_messaging_service_sid { type = string - description = "Twilio account messagin service SID (check twilio documentation)" + description = "Twilio account messaging service SID (check twilio documentation)" + default = "" +} + +variable attestation_service_twilio_verify_service_sid { + type = string + description = "Twilio account verify service SID (check twilio documentation)" default = "" } diff --git a/packages/terraform-modules-public/gcp/example/README.md b/packages/terraform-modules-public/gcp/example/README.md index 835145dcda6..ec311f55364 100644 --- a/packages/terraform-modules-public/gcp/example/README.md +++ b/packages/terraform-modules-public/gcp/example/README.md @@ -132,6 +132,7 @@ nexmo_blacklist = "" twilio_account_sid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" twilio_messaging_service_sid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + twilio_verify_service_sid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" twilio_auth_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" twilio_blacklist = "" } diff --git a/packages/terraform-modules-public/gcp/example/main.tf b/packages/terraform-modules-public/gcp/example/main.tf index 027d28e69c0..b3bce24d4a8 100644 --- a/packages/terraform-modules-public/gcp/example/main.tf +++ b/packages/terraform-modules-public/gcp/example/main.tf @@ -115,6 +115,7 @@ module "celo_cluster" { attestation_service_nexmo_unsupported_regions = var.attestation_service_credentials["nexmo_unsupported_regions"] attestation_service_twilio_account_sid = var.attestation_service_credentials["twilio_account_sid"] attestation_service_twilio_messaging_service_sid = var.attestation_service_credentials["twilio_messaging_service_sid"] + attestation_service_twilio_verify_service_sid = var.attestation_service_credentials["twilio_verify_service_sid"] attestation_service_twilio_auth_token = var.attestation_service_credentials["twilio_auth_token"] attestation_service_twilio_blacklist = var.attestation_service_credentials["twilio_blacklist"] attestation_service_twilio_unsupported_regions = var.attestation_service_credentials["twilio_unsupported_regions"] diff --git a/packages/terraform-modules-public/gcp/example/terraform.tfvars.example b/packages/terraform-modules-public/gcp/example/terraform.tfvars.example index 82f2d51b382..b009532fa7c 100644 --- a/packages/terraform-modules-public/gcp/example/terraform.tfvars.example +++ b/packages/terraform-modules-public/gcp/example/terraform.tfvars.example @@ -71,6 +71,7 @@ attestation_service_credentials = { nexmo_unsupported_regions = "CU,SY,KP,IR,SD" twilio_account_sid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" twilio_messaging_service_sid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + twilio_verify_service_sid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" twilio_auth_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" twilio_blacklist = "CU,SY,KP,IR,SD" twilio_unsupported_regions = "CU,SY,KP,IR,SD" diff --git a/packages/terraform-modules-public/gcp/example/variables.tf b/packages/terraform-modules-public/gcp/example/variables.tf index 639512f3bf8..cd51c5fd375 100644 --- a/packages/terraform-modules-public/gcp/example/variables.tf +++ b/packages/terraform-modules-public/gcp/example/variables.tf @@ -189,6 +189,7 @@ variable attestation_service_credentials { nexmo_unsupported_regions = "CU,SY,KP,IR,SD" twilio_account_sid = "secret in terraform.tfvars" twilio_messaging_service_sid = "secret in terraform.tfvars" + twilio_verify_service_sid = "secret in terraform.tfvars" twilio_auth_token = "secret in terraform.tfvars" twilio_blacklist = "CU,SY,KP,IR,SD,BY,TD,CZ,EG,ID,IL,CI,JP,JO,KZ,KE,KW,LB,MW,MX,MA,NP,NG,OM,PK,PS,PH,QA,RU,SA,LK,TZ,TH,TN,TR,AE,UA,VN,ZM,ZW" twilio_unsupported_regions = "CU,SY,KP,IR,SD,BY,TD,CZ,EG,ID,IL,CI,JP,JO,KZ,KE,KW,LB,MW,MX,MA,NP,NG,OM,PK,PS,PH,QA,RU,SA,LK,TZ,TH,TN,TR,AE,UA,VN,ZM,ZW" diff --git a/scripts/run-docker-validator-network.sh b/scripts/run-docker-validator-network.sh index ee088676b41..caceebde22c 100755 --- a/scripts/run-docker-validator-network.sh +++ b/scripts/run-docker-validator-network.sh @@ -21,6 +21,7 @@ export VALIDATOR_GROUP_NAME=tijuana_$(cat /dev/urandom | tr -dc 'a-z0-9' | fold export CELOCLI="npx celocli" export TWILIO_MESSAGING_SERVICE_SID=MG00000000000000000000000000000000 +export TWILIO_VERIFY_SERVICE_SID=VA00000000000000000000000000000000 export TWILIO_ACCOUNT_SID=AC00000000000000000000000000000000 export TWILIO_BLACKLIST="" export TWILIO_AUTH_TOKEN="ffffffffffffffffffffffffffffffff" @@ -288,7 +289,7 @@ if [[ $COMMAND == *"run-attestation"* ]]; then export CELO_PROVIDER=http://localhost:8545 echo -e "\tStarting attestation service" - screen -S celo-attestation-service -d -m docker run --name celo-attestation-service -it --restart always --entrypoint /bin/bash --network host -e ATTESTATION_SIGNER_ADDRESS=0x$CELO_ATTESTATION_SIGNER_ADDRESS -e CELO_VALIDATOR_ADDRESS=0x$CELO_VALIDATOR_ADDRESS -e CELO_PROVIDER=$CELO_PROVIDER -e DATABASE_URL=$DATABASE_URL -e SMS_PROVIDERS=twilio -e TWILIO_MESSAGING_SERVICE_SID=$TWILIO_MESSAGING_SERVICE_SID -e TWILIO_ACCOUNT_SID=$TWILIO_ACCOUNT_SID -e TWILIO_BLACKLIST=$TWILIO_BLACKLIST -e TWILIO_AUTH_TOKEN=$TWILIO_AUTH_TOKEN -e PORT=80 -p 80:80 $CELO_IMAGE_ATTESTATION -c " cd /celo-monorepo/packages/attestation-service && yarn run db:migrate && yarn start " + screen -S celo-attestation-service -d -m docker run --name celo-attestation-service -it --restart always --entrypoint /bin/bash --network host -e ATTESTATION_SIGNER_ADDRESS=0x$CELO_ATTESTATION_SIGNER_ADDRESS -e CELO_VALIDATOR_ADDRESS=0x$CELO_VALIDATOR_ADDRESS -e CELO_PROVIDER=$CELO_PROVIDER -e DATABASE_URL=$DATABASE_URL -e SMS_PROVIDERS=twilio -e TWILIO_MESSAGING_SERVICE_SID=$TWILIO_MESSAGING_SERVICE_SID -e TWILIO_VERIFY_SERVICE_SID=$TWILIO_VERIFY_SERVICE_SID -e TWILIO_ACCOUNT_SID=$TWILIO_ACCOUNT_SID -e TWILIO_BLACKLIST=$TWILIO_BLACKLIST -e TWILIO_AUTH_TOKEN=$TWILIO_AUTH_TOKEN -e PORT=80 -p 80:80 $CELO_IMAGE_ATTESTATION -c " cd /celo-monorepo/packages/attestation-service && yarn run db:migrate && yarn start " echo -e "\tAttestation service should be running, you can check running 'screen -ls'" echo -e "\tYou can re-attach to the attestation-service node running:" diff --git a/scripts/validator-config.rc b/scripts/validator-config.rc index 857b7fbbff0..d612f8b71da 100644 --- a/scripts/validator-config.rc +++ b/scripts/validator-config.rc @@ -6,6 +6,7 @@ #VALIDATOR_NAME="validator-0" #TWILIO_MESSAGING_SERVICE_SID= +#TWILIO_VERIFY_SERVICE_SID= #TWILIO_ACCOUNT_SID= #TWILIO_BLACKLIST="" #TWILIO_AUTH_TOKEN=""