diff --git a/app/build.gradle b/app/build.gradle index 0b96d27..de64a26 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -70,6 +70,7 @@ dependencies { implementation("io.ktor:ktor-server-netty:$ktor_version") implementation("io.ktor:ktor-server-cors:$ktor_version") implementation("io.ktor:ktor-server-compression:$ktor_version") + implementation "io.ktor:ktor-server-status-pages:$ktor_version" implementation("io.ktor:ktor-server-content-negotiation:$ktor_version") implementation("io.ktor:ktor-serialization-gson:$ktor_version") diff --git a/app/src/main/java/me/capcom/smsgateway/modules/gateway/GatewayModule.kt b/app/src/main/java/me/capcom/smsgateway/modules/gateway/GatewayModule.kt index 4125c2d..de54992 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/gateway/GatewayModule.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/gateway/GatewayModule.kt @@ -169,7 +169,8 @@ class GatewayModule( ), SendParams( message.withDeliveryReport ?: true, - message.simNumber + skipPhoneValidation = true, + simNumber = message.simNumber, ) ) messagesService.enqueueMessage(request) diff --git a/app/src/main/java/me/capcom/smsgateway/modules/localserver/WebService.kt b/app/src/main/java/me/capcom/smsgateway/modules/localserver/WebService.kt index 2442c08..27cf2dd 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/localserver/WebService.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/localserver/WebService.kt @@ -26,6 +26,7 @@ import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty import io.ktor.server.plugins.contentnegotiation.ContentNegotiation import io.ktor.server.plugins.cors.routing.CORS +import io.ktor.server.plugins.statuspages.StatusPages import io.ktor.server.request.receive import io.ktor.server.response.respond import io.ktor.server.routing.get @@ -69,14 +70,25 @@ class WebService : Service() { } } } - routing { - install(ContentNegotiation) { - gson { - if (me.capcom.smsgateway.BuildConfig.DEBUG) { - setPrettyPrinting() - } + install(ContentNegotiation) { + gson { + if (me.capcom.smsgateway.BuildConfig.DEBUG) { + setPrettyPrinting() } } + } + install(StatusPages) { + exception { call, cause -> + call.respond( + when (cause) { + is IllegalArgumentException -> HttpStatusCode.BadRequest + else -> HttpStatusCode.InternalServerError + }, + mapOf("message" to cause.message) + ) + } + } + routing { install(CORS) { anyHost() allowHeader(HttpHeaders.ContentType) @@ -109,35 +121,27 @@ class WebService : Service() { mapOf("message" to "simNumber must be >= 1") ) } + val skipPhoneValidation = + call.request.queryParameters["skipPhoneValidation"] + ?.toBooleanStrict() ?: false - val messageId = try { - val sendRequest = SendRequest( - MessageSource.Local, - me.capcom.smsgateway.modules.messages.data.Message( - request.id ?: NanoIdUtils.randomNanoId(), - request.message, - request.phoneNumbers, - request.isEncrypted ?: false - ), - me.capcom.smsgateway.modules.messages.data.SendParams( - request.withDeliveryReport ?: true, - request.simNumber - ) + val sendRequest = SendRequest( + MessageSource.Local, + me.capcom.smsgateway.modules.messages.data.Message( + request.id ?: NanoIdUtils.randomNanoId(), + request.message, + request.phoneNumbers, + request.isEncrypted ?: false + ), + me.capcom.smsgateway.modules.messages.data.SendParams( + request.withDeliveryReport ?: true, + skipPhoneValidation = skipPhoneValidation, + simNumber = request.simNumber, ) - messagesService.enqueueMessage(sendRequest) + ) + messagesService.enqueueMessage(sendRequest) - sendRequest.message.id - } catch (e: IllegalArgumentException) { - return@post call.respond( - HttpStatusCode.BadRequest, - mapOf("message" to e.message) - ) - } catch (e: Throwable) { - return@post call.respond( - HttpStatusCode.InternalServerError, - mapOf("message" to e.message) - ) - } + val messageId = sendRequest.message.id call.respond( HttpStatusCode.Accepted, diff --git a/app/src/main/java/me/capcom/smsgateway/modules/messages/MessagesService.kt b/app/src/main/java/me/capcom/smsgateway/modules/messages/MessagesService.kt index 62d5882..5d6daf4 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/messages/MessagesService.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/messages/MessagesService.kt @@ -135,13 +135,7 @@ class MessagesService( try { sendSMS( - message.message.id, - message.message.text, - message.recipients.filter { it.state == Message.State.Pending } - .map { it.phoneNumber }, - request.params.simNumber?.let { it - 1 }, - request.params.withDeliveryReport, - message.message.isEncrypted + request ) } catch (e: Exception) { e.printStackTrace() @@ -181,22 +175,21 @@ class MessagesService( } private suspend fun sendSMS( - id: String, - message: String, - recipients: List, - simNumber: Int?, - withDeliveryReport: Boolean, - isEncrypted: Boolean + request: SendRequest ) { - val smsManager: SmsManager = getSmsManager(simNumber) + val message = request.message + val params = request.params + val id = message.id + + val smsManager: SmsManager = getSmsManager(params.simNumber?.let { it - 1 }) @Suppress("NAME_SHADOWING") - val message = when (isEncrypted) { - true -> encryptionService.decrypt(message) - false -> message + val messageText = when (message.isEncrypted) { + true -> encryptionService.decrypt(message.text) + false -> message.text } - recipients.forEach { + message.phoneNumbers.forEach { val sentIntent = PendingIntent.getBroadcast( context, 0, @@ -208,7 +201,7 @@ class MessagesService( ), PendingIntent.FLAG_IMMUTABLE ) - val deliveredIntent = when (withDeliveryReport) { + val deliveredIntent = when (params.withDeliveryReport) { false -> null true -> PendingIntent.getBroadcast( context, @@ -224,13 +217,16 @@ class MessagesService( } try { - val parts = smsManager.divideMessage(message) - val phoneNumber = when (isEncrypted) { + val parts = smsManager.divideMessage(messageText) + val phoneNumber = when (message.isEncrypted) { true -> encryptionService.decrypt(it) false -> it } - val normalizedPhoneNumber = - PhoneHelper.filterPhoneNumber(phoneNumber, countryCode ?: "RU") + val normalizedPhoneNumber = when (params.skipPhoneValidation) { + true -> phoneNumber.filter { it.isDigit() || it == '+' } + false -> PhoneHelper.filterPhoneNumber(phoneNumber, countryCode ?: "RU") + } + if (parts.size > 1) { smsManager.sendMultipartTextMessage( normalizedPhoneNumber, @@ -243,7 +239,7 @@ class MessagesService( smsManager.sendTextMessage( normalizedPhoneNumber, null, - message, + messageText, sentIntent, deliveredIntent ) diff --git a/app/src/main/java/me/capcom/smsgateway/modules/messages/data/SendParams.kt b/app/src/main/java/me/capcom/smsgateway/modules/messages/data/SendParams.kt index 9e65a21..fb391bf 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/messages/data/SendParams.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/messages/data/SendParams.kt @@ -2,5 +2,9 @@ package me.capcom.smsgateway.modules.messages.data class SendParams( val withDeliveryReport: Boolean, + val skipPhoneValidation: Boolean, + /** + * Sim number (from 1 to 3) + */ val simNumber: Int? = null, ) \ No newline at end of file diff --git a/docs/api/swagger.json b/docs/api/swagger.json index 42ee88b..4d4368a 100644 --- a/docs/api/swagger.json +++ b/docs/api/swagger.json @@ -33,6 +33,17 @@ "summary": "Send message", "description": "Adds a message to the queue for sending", "operationId": "post-message", + "parameters": [ + { + "name": "skipPhoneValidation", + "in": "query", + "description": "if `true` phone numbers will be used as is", + "schema": { + "type": "boolean", + "default": false + } + } + ], "requestBody": { "$ref": "#/components/requestBodies/SendMessageRequest" }, @@ -202,10 +213,16 @@ "ttl": { "type": "integer", "nullable": true, - "description": "*(cloud-only)* message storage time in `Pending` state, `null` - forever", + "description": "expiration timeout, conflicts with `validUntil`", "minimum": 5, "example": 86400 }, + "validUntil": { + "type": "string", + "nullable": true, + "description": "expiration date, conflicts with `ttl`", + "format": "date-time" + }, "withDeliveryReport": { "type": "boolean", "description": "request delivery report",