diff --git a/.gitignore b/.gitignore
index ab5b6dea..9ac840ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,7 @@ build/
.idea/
local.properties
*.iml
+**/.terraform/*
+*.tfstate
+*.tfstate.*
+crash.log
diff --git a/build.gradle b/build.gradle
index ddd2e3a9..82372bc8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,7 @@
plugins {
id 'com.google.protobuf' version '0.8.17' apply false
id 'com.google.cloud.tools.jib' version '3.1.4' apply false
+ id 'org.ysb33r.terraform' version '0.12.2'
}
allprojects {
@@ -81,6 +82,15 @@ subprojects {
}
}
+terraformSourceSets {
+ dev {
+ srcDir = 'terraform'
+ variables {
+ file 'env/dev.tfvars'
+ }
+ }
+}
+
static def gitVersion() {
return 'git describe --tags --always --first-parent'.execute().text.trim()
}
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 6ccc75f9..dbff3ebd 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -2184,6 +2184,14 @@
+
+
+
+
+
+
+
+
@@ -3738,6 +3746,14 @@
+
+
+
+
+
+
+
+
@@ -3783,6 +3799,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -4033,5 +4102,13 @@
+
+
+
+
+
+
+
+
diff --git a/localstack/docker-compose.yml b/localstack/docker-compose.yml
new file mode 100644
index 00000000..622874bb
--- /dev/null
+++ b/localstack/docker-compose.yml
@@ -0,0 +1,58 @@
+version: "2.4"
+
+services:
+ accountdb:
+ image: postgres:14.0-alpine
+ user: "postgres"
+ healthcheck:
+ test: [ CMD-SHELL, "pg_isready -d accounts" ]
+ ports:
+ - "5432:5432"
+ environment:
+ - "POSTGRES_HOST_AUTH_METHOD=trust"
+ - "POSTGRES_DB=accounts"
+ volumes:
+ - "dev-accountdb-data:/var/lib/postgresql/data"
+
+ abusedb:
+ image: postgres:14.0-alpine
+ user: "postgres"
+ healthcheck:
+ test: [ CMD-SHELL, "pg_isready -d abuse" ]
+ ports:
+ - "5433:5432"
+ environment:
+ - "POSTGRES_HOST_AUTH_METHOD=trust"
+ - "POSTGRES_DB=abuse"
+ volumes:
+ - "dev-abusedb-data:/var/lib/postgresql/data"
+
+ redis-cluster:
+ image: grokzen/redis-cluster:6.2.0
+ ports:
+ - "7000-7002:7000-7002"
+ healthcheck:
+ test: [ CMD-SHELL, "redis-cli -p 7000 cluster info | grep ^cluster_state:ok" ]
+ environment:
+ - "SLAVES_PER_MASTER=0"
+ - "IP=0.0.0.0"
+ volumes:
+ - "dev-redis-data:/redis-data"
+
+ localstack:
+ image: localstack/localstack:0.12.19.1
+ healthcheck:
+ test: [ CMD-SHELL, "awslocal dynamodb list-tables && awslocal s3 ls" ]
+ ports:
+ - "4566:4566"
+ environment:
+ - "SERVICES=dynamodb,s3,sts"
+ - "DATA_DIR=/tmp/localstack/data"
+ volumes:
+ - "dev-localstack-data:/tmp/localstack"
+
+volumes:
+ dev-accountdb-data:
+ dev-abusedb-data:
+ dev-redis-data:
+ dev-localstack-data:
diff --git a/service/build.gradle b/service/build.gradle
index 1cd7cfea..cb9951f3 100644
--- a/service/build.gradle
+++ b/service/build.gradle
@@ -114,3 +114,26 @@ jib {
image = 'sweetlies-whisper-service:latest'
}
}
+
+def devRuntimeEnvironment = [
+ AWS_REGION : "us-east-2",
+ AWS_ACCESS_KEY_ID : "test",
+ AWS_SECRET_ACCESS_KEY : "test",
+ AWS_ENDPOINT_OVERRIDE : "http://localhost:4566",
+ AWS_EC2_METADATA_DISABLED: "true",
+ ACCOUNTS_DB_URL : "jdbc:postgresql://localhost:5432/accounts",
+ ABUSE_DB_URL : "jdbc:postgresql://localhost:5433/abuse",
+ REDIS_CLUSTER_BASE_URL : "redis://localhost:7000"
+]
+
+task runServer(type: JavaExec) {
+ group = 'Application'
+ classpath = sourceSets.main.runtimeClasspath
+ getMainClass().set application.getMainClass()
+
+ if (args.isEmpty()) {
+ args(['server', 'config/dev.yml'])
+ }
+
+ environment(devRuntimeEnvironment)
+}
diff --git a/service/src/main/resources/config/dev.yml b/service/src/main/resources/config/dev.yml
new file mode 100644
index 00000000..c593a005
--- /dev/null
+++ b/service/src/main/resources/config/dev.yml
@@ -0,0 +1,293 @@
+server:
+ applicationConnectors:
+ - type: http
+ bindHost: ${HTTP_HOST:-127.0.0.1}
+ port: ${HTTP_PORT:-8080}
+ adminConnectors:
+ - type: http
+ bindHost: ${ADMIN_HOST:-127.0.0.1}
+ port: ${ADMIN_HTTP_PORT:-8081}
+
+dynamoDbClientConfiguration:
+ region: ${AWS_REGION}
+
+twilio: # Twilio gateway configuration
+ accountId: test
+ accountToken: test
+ nanpaMessagingServiceSid: test
+ messagingServiceSid: test
+ verifyServiceSid: test
+ localDomain: test
+ defaultClientVerificationTexts:
+ ios: test
+ androidNg: test
+ android202001: test
+ android202103: test
+ generic: test
+ androidAppHash: test
+ verifyServiceFriendlyName: test
+
+push:
+ queueSize: # Size of push pending queue
+
+turn: # TURN server configuration
+ secret: test
+ uris:
+ - stun:test:80
+ - stun:test:443
+ - turn:test:443?transport=udpq
+ - turn:test:80?transport=udp
+
+cacheCluster: # Redis server configuration for cache cluster
+ configurationUri: ${REDIS_CLUSTER_BASE_URL}/1
+ timeout: 30
+
+clientPresenceCluster: # Redis server configuration for client presence cluster
+ configurationUri: ${REDIS_CLUSTER_BASE_URL}/2
+ timeout: 30
+
+pubsub: # Redis server configuration for pubsub cluster
+ url: ${REDIS_CLUSTER_BASE_URL}/0
+ replicaUrls:
+ - ${REDIS_CLUSTER_BASE_URL}/0
+
+pushSchedulerCluster: # Redis server configuration for push scheduler cluster
+ configurationUri: ${REDIS_CLUSTER_BASE_URL}/3
+ timeout: 30
+
+rateLimitersCluster: # Redis server configuration for rate limiters cluster
+ configurationUri: ${REDIS_CLUSTER_BASE_URL}/4
+ timeout: 30
+
+messageCache: # Redis server configuration for message store cache
+ cluster:
+ configurationUri: ${REDIS_CLUSTER_BASE_URL}/5
+ timeout: 30
+
+metricsCluster:
+ configurationUri: ${REDIS_CLUSTER_BASE_URL}/6
+ timeout: 30
+
+messageDynamoDb: # DynamoDB table configuration
+ region: ${AWS_REGION}
+ tableName: Messages
+
+keysDynamoDb: # DynamoDB table configuration
+ region: ${AWS_REGION}
+ tableName: Keys
+
+accountsDynamoDb: # DynamoDB table configuration
+ region: ${AWS_REGION}
+ tableName: Accounts
+ phoneNumberTableName: PhoneNumbers
+
+deletedAccountsDynamoDb: # DynamoDb table configuration
+ region: ${AWS_REGION}
+ tableName: DeleteAccounts
+
+deletedAccountsLockDynamoDb: # DynamoDb table configuration
+ region: ${AWS_REGION}
+ tableName: DeleteAccountsLock
+
+pendingAccountsDynamoDb: # DynamoDB table configuration
+ region: ${AWS_REGION}
+ tableName: PendingAccounts
+
+pendingDevicesDynamoDb: # DynamoDB table configuration
+ region: ${AWS_REGION}
+ tableName: PendingDevices
+
+pushChallengeDynamoDb: # DynamoDB table configuration
+ region: ${AWS_REGION}
+ tableName: PushChallenges
+
+reportMessageDynamoDb: # DynamoDB table configuration
+ region: ${AWS_REGION}
+ tableName: ReportMessages
+
+awsAttachments: # AWS S3 configuration
+ accessKey: test
+ accessSecret: test
+ bucket: attachments
+ region: ${AWS_REGION}
+
+gcpAttachments: # GCP Storage configuration
+ domain: test
+ email: test
+ maxSizeInBytes: 1
+ rsaSigningKey: |
+ -----BEGIN PRIVATE KEY-----
+ MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet
+ 8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk
+ FPZk/7x0xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAv
+ SKAFKEvyD43si00DQnXWrYHAEQIDAQABAoGAAPy5SiYHiVErU3KR4Bg+pl4x75wM
+ FiRC0Cgz+frQPFQEBsAV9RuasyQxqzxrR0Ow0qncBeGBWbYE6WZhqtcLAI895b+i
+ +F4lbB4iD7T9QeIDMV/aIMXA81UO4cns1z4qDAHKeyLLrPQrJ/B4X7XC+egUWm5+
+ hr1qmyAMusyXIBECQQDJWZ8piluf4yrYfsJAn6hF5T4RjTztbqvO0GVG2McHY7Uj
+ NPSffhzHx/ll0fQEQji+OgydCCX8o3HZrgw5YfSJAkEA7e+rqdU5nO5ZG//PSEQb
+ tjLnRiTzBH/elQhtdZ5nF7pcpNTi4k13zutmKcWW4GK75azcRGJUhu1kDM7QYAOd
+ SQJAVNkYcifkvna7GmooL5VYEsQsqLbM4v0NF2TIGNfG3z1MGp75KrC5LhL97MNR
+ we2p/bd2k0HYyCKUGnf2nMPDiQJBAI75pwittSoE240EobUGIDTSz8CJsXIxuDmL
+ z+KOpdpPRR5TQmbEMEspjsFpFymMiuYPgmihQbO2cJl1qScY5OkCQQCJ6m5tcN8l
+ Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/
+ mu/UpE/BRZmR
+ -----END PRIVATE KEY-----
+
+abuseDatabase: # Postgresql database configuration
+ driverClass: org.postgresql.Driver
+ user: postgres
+ password: postgres
+ url: ${ABUSE_DB_URL}
+
+accountsDatabase: # Postgresql database configuration
+ driverClass: org.postgresql.Driver
+ user: postgres
+ password: postgres
+ url: ${ACCOUNTS_DB_URL}
+
+accountDatabaseCrawler:
+ chunkSize: # accounts per run
+ chunkIntervalMs: # time per run
+
+apn: # Apple Push Notifications configuration
+ sandbox: true
+ bundleId: test
+ keyId: test
+ teamId: test
+ signingKey: |
+ -----BEGIN PRIVATE KEY-----
+ MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgir767IOFOYHsYtNQ
+ wsvLeJVu3bxCLL/SURQvMZw6QumgCgYIKoZIzj0DAQehRANCAARuwGOLtHY99zLl
+ iyACJp6xmj6YfE8bOLxHTZGkoC/+yNgf/fBpwf5Nin2pzyM8FUOYXg1R1v2bQqJy
+ wHYtSkc1
+ -----END PRIVATE KEY----
+
+gcm: # GCM Configuration
+ senderId: 9999
+ apiKey: test
+
+cdn:
+ accessKey: test
+ accessSecret: test
+ bucket: CDN
+ region: ${AWS_REGION}
+
+datadog:
+ apiKey: test
+ environment: test
+
+unidentifiedDelivery:
+ certificate: CiUIARIhBaXYSgI1RJwALheDXpRKOhaJR8pR7BFKiJeWIxcWiycdEkCcrSomdnUf40mP8tU1tG0ZGRpjlaJHkGOS+FxBruC6MMcd27YgfJLKMCmh6A29REwG5BYhN3bFjmyh1sT8GrsL
+ privateKey: ILk+eFEBzWXLVTBeltxxAiz2AeY4iWdV0XFlV21+aX8=
+ expiresDays: 356
+
+voiceVerification:
+ url: test
+ locales:
+ - en
+
+recaptcha:
+ secret: test
+
+recaptchaV2:
+ siteKey: test
+ scoreFloor: 1.0
+ projectPath: test
+ credentialConfigurationJson: |
+ {
+ "type": "service_account",
+ "project_id": "project-id",
+ "private_key_id": "d84a4fefcf50791d4a90f2d7af17469d6282df9d",
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALX0PQoe1igW12ikv1bN/r9lN749y2ijmbc/mFHPyS3hNTyOCjDvBbXYbDhQJzWVUikh4mvGBA07qTj79Xc3yBDfKP2IeyYQIFe0t0zkd7R9Zdn98Y2rIQC47aAbDfubtkU1U72t4zL11kHvoa0/RuFZjncvlr42X7be7lYh4p3NAgMBAAECgYASk5wDw4Az2ZkmeuN6Fk/y9H+Lcb2pskJIXjrL533vrDWGOC48LrsThMQPv8cxBky8HFSEklPpkfTF95tpD43iVwJRB/GrCtGTw65IfJ4/tI09h6zGc4yqvIo1cHX/LQ+SxKLGyir/dQM925rGt/VojxY5ryJR7GLbCzxPnJm/oQJBANwOCO6D2hy1LQYJhXh7O+RLtA/tSnT1xyMQsGT+uUCMiKS2bSKx2wxo9k7h3OegNJIu1q6nZ6AbxDK8H3+d0dUCQQDTrPSXagBxzp8PecbaCHjzNRSQE2in81qYnrAFNB4o3DpHyMMY6s5ALLeHKscEWnqP8Ur6X4PvzZecCWU9BKAZAkAutLPknAuxSCsUOvUfS1i87ex77Ot+w6POp34pEX+UWb+u5iFn2cQacDTHLV1LtE80L8jVLSbrbrlH43H0DjU5AkEAgidhycxS86dxpEljnOMCw8CKoUBd5I880IUahEiUltk7OLJYS/Ts1wbn3kPOVX3wyJs8WBDtBkFrDHW2ezth2QJADj3e1YhMVdjJW5jqwlD/VNddGjgzyunmiZg0uOXsHXbytYmsA545S8KRQFaJKFXYYFo2kOjqOiC1T2cAzMDjCQ==\n-----END PRIVATE KEY-----\n",
+ "client_email": "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr@developer.gserviceaccount.com",
+ "client_id": "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com"
+ }
+
+storageService:
+ uri: test
+ userAuthenticationTokenSharedSecret: c597c0cc3169b84b4420d206bfdb14e2
+ storageCaCertificate: |
+ -----BEGIN CERTIFICATE-----
+ MIIDlzCCAk+gAwIBAgIETadUITANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJC
+ RTEPMA0GA1UEChMGR251VExTMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTEwNDE0
+ MjAwODAyWhcNMzgwODI5MjAwODA0WjAyMQswCQYDVQQGEwJCRTEPMA0GA1UEChMG
+ R251VExTMRIwEAYDVQQDEwlsb2NhbGhvc3QwggFSMA0GCSqGSIb3DQEBAQUAA4IB
+ PwAwggE6AoIBMQDdz5fSpR2V3YYY2MS5raYMtJ223PrcIeE6YjQH6DOy6JfuLEHS
+ EvFf7eR2/2UmHgzHQRVpXw35rYkUjerXFlKaR8G7AALkiEVzeKSu2zjDxgfSZA6H
+ 7XSMa8TAAlB8TqbRWOnlEwmp21rq6w8GgFwJ75TI6fs3LnXhrJOtmzcTS2Y6djPY
+ xNdM+2HIkiEH/N+piFTko6lH0my44zmJEYg4LaLcPl5KqaSO1R+y0N1BPNoQaJ5H
+ G2UCosUocwKDAwn99Sl+l9wqTkuqeUZGcIYbm7j2ir4ph31f2qWXa+/IQwlD4h+K
+ Fn4dUF312gLu8sMqSOZrMOoC1++siwy4wYXYv3yFqB6DvlwmLnl7R/VKP2Zikv1B
+ ILYsAPBSyiYGLXzPelB9D8vdlyDIb+TgUPTjAgMBAAGjVTBTMAwGA1UdEwEB/wQC
+ MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0PAQH/BAUDAwegADAdBgNVHQ4E
+ FgQUklPWcbn4aKqzU/aN9TlFZpyn5TEwDQYJKoZIhvcNAQELBQADggExAJi/SInB
+ 5uYVE8z8uu2gieWGRTBzaLJ5H4gCgPstybghVY3Ft1Ybz8N27tDw2SI6Y5LFBIZw
+ HkIzKjvEFAjFQpJzfD45wO40xzMWX5Ouzx+aMAlR/i2UnCitKn7kFIFFaw3XESH8
+ 2ycXdLTMlBpunntYqeAGjdpfYOG4byhotli+xaw2Rzf2qDh0I4HzIr5h/wgIh+vC
+ jykldV1M69UJKKt7mflpCKLGAtIuzfrxGc4/RGqhS6hW1RGuRONoBVBXjXIPxyHb
+ j6NQeF1aOcuQPVJDM7/qiQcaksyFJ6g9NLhbUu7vILm2/+rFkNNHxVGQ4uY+Urke
+ eRi+/eIkvkcyWrADa6rbw9v2YEQItiwZR6LwQ3/wB5dXq+yguGpJzgjmw03ypOm4
+ Q+fwhNcachRdgho=
+ -----END CERTIFICATE-----
+
+backupService:
+ uri: test
+ userAuthenticationTokenSharedSecret: 231ffce57ce6542f753da437c712caab
+ backupCaCertificate: |
+ -----BEGIN CERTIFICATE-----
+ MIIDlzCCAk+gAwIBAgIETadUITANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJC
+ RTEPMA0GA1UEChMGR251VExTMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTEwNDE0
+ MjAwODAyWhcNMzgwODI5MjAwODA0WjAyMQswCQYDVQQGEwJCRTEPMA0GA1UEChMG
+ R251VExTMRIwEAYDVQQDEwlsb2NhbGhvc3QwggFSMA0GCSqGSIb3DQEBAQUAA4IB
+ PwAwggE6AoIBMQDdz5fSpR2V3YYY2MS5raYMtJ223PrcIeE6YjQH6DOy6JfuLEHS
+ EvFf7eR2/2UmHgzHQRVpXw35rYkUjerXFlKaR8G7AALkiEVzeKSu2zjDxgfSZA6H
+ 7XSMa8TAAlB8TqbRWOnlEwmp21rq6w8GgFwJ75TI6fs3LnXhrJOtmzcTS2Y6djPY
+ xNdM+2HIkiEH/N+piFTko6lH0my44zmJEYg4LaLcPl5KqaSO1R+y0N1BPNoQaJ5H
+ G2UCosUocwKDAwn99Sl+l9wqTkuqeUZGcIYbm7j2ir4ph31f2qWXa+/IQwlD4h+K
+ Fn4dUF312gLu8sMqSOZrMOoC1++siwy4wYXYv3yFqB6DvlwmLnl7R/VKP2Zikv1B
+ ILYsAPBSyiYGLXzPelB9D8vdlyDIb+TgUPTjAgMBAAGjVTBTMAwGA1UdEwEB/wQC
+ MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0PAQH/BAUDAwegADAdBgNVHQ4E
+ FgQUklPWcbn4aKqzU/aN9TlFZpyn5TEwDQYJKoZIhvcNAQELBQADggExAJi/SInB
+ 5uYVE8z8uu2gieWGRTBzaLJ5H4gCgPstybghVY3Ft1Ybz8N27tDw2SI6Y5LFBIZw
+ HkIzKjvEFAjFQpJzfD45wO40xzMWX5Ouzx+aMAlR/i2UnCitKn7kFIFFaw3XESH8
+ 2ycXdLTMlBpunntYqeAGjdpfYOG4byhotli+xaw2Rzf2qDh0I4HzIr5h/wgIh+vC
+ jykldV1M69UJKKt7mflpCKLGAtIuzfrxGc4/RGqhS6hW1RGuRONoBVBXjXIPxyHb
+ j6NQeF1aOcuQPVJDM7/qiQcaksyFJ6g9NLhbUu7vILm2/+rFkNNHxVGQ4uY+Urke
+ eRi+/eIkvkcyWrADa6rbw9v2YEQItiwZR6LwQ3/wB5dXq+yguGpJzgjmw03ypOm4
+ Q+fwhNcachRdgho=
+ -----END CERTIFICATE-----
+
+zkConfig:
+ serverPublic: ACL4V8rh4l4xF+c0dcRg5JN4G8reoEExtEdVvbU10qYY0sPn+LPGavcjNo7FbXNhpedld6n5GrmA5rPdYXNIVAKQ2ILKRGcmox4/KTmuuW32iOBznCAOuJ/rTafroBOCFUQYXA1A8wz52aYM4iqi+YwZuWs3lbolU2hAuDFLkoBDRNwftdNT2sUD1jRy+gpBimAXIBTm28O04PUBZx6KAUVyjxemiB1emO2fA6KL7/30Pna9YQe//mu5XvLElAyOR2g4qjifCZQdOfXc7BOo6CLRLPS71GkZvYhiZKxm6F8I
+ serverSecret: ACKqqtek/wIFpHPlMFRsXcfwXAI4XHOaJzQ5/OZC57kCd4KT1aUJGQHd43NKY2UYF7xiqhwQ14ol+2DoMTfDXAkS3gupCAyLArJVUD2WF/HJiV8RuxWSFu9l+Sd7r3XPXWDSXSAW2wH/JllRnCneWQfCcMTCc5wktnmmmRHPjegCxo6EAFNfgMtmHL33VS9d6XhfsxnUFd244Hoi4TZrvw5kJjOcUR+wTF1eEvKToH8G88WFHDjjcj+nGPaCmjYiBi5yjfMPLcNelcMuhPMd7nbYkfgjBGMX0UCslP/s2DsNdG7LB7XQc7289Qlc+5IsAGAaF59ZzT7UXD64w3H65AAsKlo1EIkrVdmeB2QhxrQAR1QPDMdz2GmjfOnxn5fIBiL4V8rh4l4xF+c0dcRg5JN4G8reoEExtEdVvbU10qYY0sPn+LPGavcjNo7FbXNhpedld6n5GrmA5rPdYXNIVAIr4A+uGl6MsGgZBnk6OVRciby89VENQu/beBSSU8oYAL2m6QVZ9e/ejCF052f2+pnYOlvsyoI4Sr8ByLJRp7cMkjlHsenVAQraMJ/Quyb3RaSWWHMG8GxYz7IKk/JqAUz2y60ZYgZvGA/oVCUMeut3w8X0kBMeuu0vSJCLMYQDBPVIxrL+mmGOvqFfELbLTo5ROlVks1tJ0ZiX/IJqAWAGrXqs4u/dNEFZeaIOnU2uBctJqclc2io5H7u1VcG5ag6iDzVAmgFImEpp/SV9VLanuM3vDtBrYsP0ljq1BOlOCpuOevcHYWVs/HcfMbHr/GXbrc2BjolMKLwFk6da43MMIvlPiaD67KeBBMJgaz/JylK5S+4Dr2wOlnOsI47d8w2Q2ILKRGcmox4/KTmuuW32iOBznCAOuJ/rTafroBOCFUQYXA1A8wz52aYM4iqi+YwZuWs3lbolU2hAuDFLkoBD5MJT/K1YLrmmBbyoTjRdXLpv4YZXBRKCTZLyhM8iOwNE3B+101PaxQPWNHL6CkGKYBcgFObbw7Tg9QFnHooBRZ4P9UZxpXzH9Sa1ugyf88FwtVgs6HC46rCiSmxHwh8O139WnsUpl4xXu4X9r56HpXlqXgKvSdtYhFftfow9qQGuvZCVnA/WSZmQMBfGfEDEe+J+kBSJ2XD2uib9EnUWZG1QATEH4vpQrSmwiSOp3ysLgT6zX/nDBOW3ud0sivQOFF39ephY9qylAv9Dr5jQf26JWo06iFNA5Tm0wjS+kw+zR5y2OzZL+9i/pz6YNZsL42a4vat2hySrrFuWPY1DBtLY9G5n5kpT4DuTVjCRnW4gPN98pvGhMSOdeylOxAgHj6DYlNOtDdwiDBpkl+4MlMXzNC5nKUAfpPMmD0fPVw9YBczEfFkBn6dBFxmstesl1y47jzK8TN17QqzVnmQpCXKPF6aIHV6Y7Z8Doovv/fQ+dr1hB7/+a7le8sSUDI5HaDiqOJ8JlB059dzsE6joItEs9LvUaRm9iGJkrGboXwg
+
+appConfig:
+ enabled: false
+ application: test
+ environment: test
+ configuration: test
+ region: ${AWS_REGION}
+
+remoteConfig:
+ authorizedTokens:
+ - # 1st authorized token
+ - # 2nd authorized token
+ - # ...
+ - # Nth authorized token
+ globalConfig: # keys and values that are given to clients on GET /v1/config
+ test: test
+
+paymentsService:
+ fixerApiKey: test
+ paymentCurrencies:
+ -
+
+torExitNodeList:
+ s3Region: ${AWS_REGION}
+ s3Bucket: TorExitNodeList
+ objectKey: TorExitNodeList
+
+asnTable:
+ s3Region: ${AWS_REGION}
+ s3Bucket: AsnTable
+ objectKey: AsnTable
diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl
new file mode 100644
index 00000000..1b4c1b44
--- /dev/null
+++ b/terraform/.terraform.lock.hcl
@@ -0,0 +1,20 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "3.63.0"
+ hashes = [
+ "h1:v9aPF3aaBpk0uSO5pfggYJKGgP/Ur28hZRJs1jS+ttI=",
+ "zh:42c6c98b294953a4e1434a331251e539f5372bf6779bd61ab5df84cac0545287",
+ "zh:5493773762a470889c9a23db97582d3a82035847c8d3bd13323b4c3012abf325",
+ "zh:550d22ff9fed4d817a922e7b84bd9d1f2ef8d3afa00832cf66b8cd5f0e6dc748",
+ "zh:632cb5e2d9d5041875f57174236eafe5b05dbf26750c1041ab57eb08c5369fe2",
+ "zh:7cfeaf5bde1b28bd010415af1f3dc494680a8374f1a26ec19db494d99938cc4e",
+ "zh:99d871606b67c8aefce49007315de15736b949c09a9f8f29ad8af1e9ce383ed3",
+ "zh:c4fc8539ffe90df5c7ae587fde495fac6bc0186fec2f2713a8988a619cef265f",
+ "zh:d0a26493206575c99ca221d78fe64f96a8fbcebe933af92eea6b39168c1f1c1d",
+ "zh:e156fdc964fdd4a7586ec15629e20d2b06295b46b4962428006e088145db07d6",
+ "zh:eb04fc80f652b5c92f76822f0fec1697581543806244068506aed69e1bb9b2af",
+ "zh:f5638a533cf9444f7d02b5527446cdbc3b2eab8bcc4ec4b0ca32035fe6f479d3",
+ ]
+}
diff --git a/terraform/env/dev.tfvars b/terraform/env/dev.tfvars
new file mode 100644
index 00000000..b8c3bdd4
--- /dev/null
+++ b/terraform/env/dev.tfvars
@@ -0,0 +1,4 @@
+aws_deploy_region = "us-east-2"
+aws_access_key = "test"
+aws_secret_key = "test"
+aws_endpoint = "http://localhost:4566"
diff --git a/terraform/main.tf b/terraform/main.tf
new file mode 100644
index 00000000..c8326fd2
--- /dev/null
+++ b/terraform/main.tf
@@ -0,0 +1,188 @@
+provider "aws" {
+ region = var.aws_deploy_region
+ access_key = var.aws_access_key
+ secret_key = var.aws_secret_key
+
+ skip_metadata_api_check = (var.aws_endpoint != null)
+
+ endpoints {
+ dynamodb = var.aws_endpoint
+ s3 = var.aws_endpoint
+ sts = var.aws_endpoint
+ }
+}
+
+resource "aws_dynamodb_table" "messages" {
+ name = "Messages"
+ hash_key = "H"
+ range_key = "S"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_PARTITION
+ name = "H"
+ type = "B"
+ }
+
+ attribute { # KEY_SORT
+ name = "S"
+ type = "B"
+ }
+
+ attribute { # LOCAL_INDEX_MESSAGE_UUID_KEY_SORT
+ name = "U"
+ type = "B"
+ }
+
+ local_secondary_index {
+ name = "Message_UUID_Index"
+ projection_type = "KEYS_ONLY"
+ range_key = "U"
+ }
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "keys" {
+ name = "Keys"
+ hash_key = "U"
+ range_key = "DK"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_ACCOUNT_UUID
+ name = "U"
+ type = "B"
+ }
+
+ attribute { # KEY_DEVICE_ID_KEY_ID
+ name = "DK"
+ type = "B"
+ }
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "accounts" {
+ name = "Accounts"
+ hash_key = "U"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_ACCOUNT_UUID
+ name = "U"
+ type = "B"
+ }
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "phone_numbers" {
+ name = "PhoneNumbers"
+ hash_key = "P"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # ATTR_ACCOUNT_E164
+ name = "P"
+ type = "S"
+ }
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "deleted_accounts" {
+ name = "DeleteAccounts"
+ hash_key = "P"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_ACCOUNT_E164
+ name = "P"
+ type = "S"
+ }
+
+ // TODO: Set TTL
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "deleted_accounts_lock" {
+ name = "DeleteAccountsLock"
+ hash_key = "P"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_ACCOUNT_E164
+ name = "P"
+ type = "S"
+ }
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "pending_accounts" {
+ name = "PendingAccounts"
+ hash_key = "P"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_ACCOUNT_E164
+ name = "P"
+ type = "S"
+ }
+
+ ttl { # ATTR_TTL
+ enabled = true
+ attribute_name = "E"
+ }
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "pending_devices" {
+ name = "PendingDevices"
+ hash_key = "P"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_ACCOUNT_E164
+ name = "P"
+ type = "S"
+ }
+
+ ttl { # ATTR_TTL
+ enabled = true
+ attribute_name = "E"
+ }
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "push_challenges" {
+ name = "PushChallenges"
+ hash_key = "U"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_ACCOUNT_UUID
+ name = "U"
+ type = "B"
+ }
+
+ ttl { # ATTR_TTL
+ enabled = true
+ attribute_name = "T"
+ }
+
+ tags = {}
+}
+
+resource "aws_dynamodb_table" "report_messages" {
+ name = "ReportMessages"
+ hash_key = "H"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute { # KEY_HASH
+ name = "H"
+ type = "B"
+ }
+
+ ttl { # ATTR_TTL
+ enabled = true
+ attribute_name = "E"
+ }
+
+ tags = {}
+}
diff --git a/terraform/variables.tf b/terraform/variables.tf
new file mode 100644
index 00000000..5433db48
--- /dev/null
+++ b/terraform/variables.tf
@@ -0,0 +1,18 @@
+variable "aws_deploy_region" {
+ type = string
+}
+
+variable "aws_endpoint" {
+ type = string
+ default = null
+}
+
+variable "aws_access_key" {
+ type = string
+ default = null
+}
+
+variable "aws_secret_key" {
+ type = string
+ default = null
+}
diff --git a/terraform/versions.tf b/terraform/versions.tf
new file mode 100644
index 00000000..7117131f
--- /dev/null
+++ b/terraform/versions.tf
@@ -0,0 +1,3 @@
+terraform {
+ required_version = ">= 1.0"
+}