Skip to content

Commit 6b44548

Browse files
committed
[localserver] add ability to change port and credentials, see #138
1 parent 9572a2d commit 6b44548

File tree

13 files changed

+245
-46
lines changed

13 files changed

+245
-46
lines changed

app/src/main/java/me/capcom/smsgateway/helpers/SettingsHelper.kt

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import android.content.Context
55
import android.content.pm.PackageManager
66
import androidx.core.content.edit
77
import androidx.preference.PreferenceManager
8-
import com.aventrix.jnanoid.jnanoid.NanoIdUtils
98
import me.capcom.smsgateway.receivers.BootReceiver
109

1110
class SettingsHelper(private val context: Context) {
1211
private val settings = PreferenceManager.getDefaultSharedPreferences(context)
1312

13+
init {
14+
migrate()
15+
}
16+
1417
var autostart: Boolean
1518
get() = settings.getBoolean(PREF_KEY_AUTOSTART, false)
1619
set(value) {
@@ -24,30 +27,24 @@ class SettingsHelper(private val context: Context) {
2427
settings.edit { putBoolean(PREF_KEY_AUTOSTART, value) }
2528
}
2629

27-
var serverPort: Int
28-
get() = settings.getInt(PREF_KEY_SERVER_PORT, 8080)
29-
set(value) = settings.edit { putInt(PREF_KEY_SERVER_PORT, value) }
30-
31-
var serverToken: String
32-
get() = settings.getString(PREF_KEY_SERVER_TOKEN, null)
33-
?: NanoIdUtils.randomNanoId(
34-
NanoIdUtils.DEFAULT_NUMBER_GENERATOR,
35-
NanoIdUtils.DEFAULT_ALPHABET,
36-
8
37-
)
38-
.also { serverToken = it }
39-
set(value) = settings.edit { putString(PREF_KEY_SERVER_TOKEN, value) }
40-
4130
var fcmToken: String?
4231
get() = settings.getString(PREF_KEY_FCM_TOKEN, null)
4332
set(value) = settings.edit { putString(PREF_KEY_FCM_TOKEN, value) }
4433

34+
private fun migrate() {
35+
// remove after 2025-11-28
36+
val PREF_KEY_SERVER_TOKEN = "server_token"
37+
if (settings.contains(PREF_KEY_SERVER_TOKEN)) {
38+
settings.edit(true) {
39+
putString("localserver.PASSWORD", settings.getString(PREF_KEY_SERVER_TOKEN, null))
40+
remove(PREF_KEY_SERVER_TOKEN)
41+
}
42+
}
43+
}
44+
4545
companion object {
4646
private const val PREF_KEY_AUTOSTART = "autostart"
4747

48-
private const val PREF_KEY_SERVER_PORT = "server_port"
49-
private const val PREF_KEY_SERVER_TOKEN = "server_token"
50-
5148
private const val PREF_KEY_FCM_TOKEN = "fcm_token"
5249
}
5350
}

app/src/main/java/me/capcom/smsgateway/modules/localserver/LocalServerSettings.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package me.capcom.smsgateway.modules.localserver
22

3+
import com.aventrix.jnanoid.jnanoid.NanoIdUtils
34
import me.capcom.smsgateway.modules.settings.KeyValueStorage
45
import me.capcom.smsgateway.modules.settings.get
56

@@ -14,9 +15,26 @@ class LocalServerSettings(
1415
get() = storage.get<String?>(DEVICE_ID)
1516
set(value) = storage.set(DEVICE_ID, value)
1617

18+
val port: Int
19+
get() = storage.get<Int>(PORT) ?: 8080
20+
21+
val username: String
22+
get() = storage.get<String?>(USERNAME)
23+
?: "sms"
24+
val password: String
25+
get() = storage.get<String?>(PASSWORD)
26+
?: NanoIdUtils.randomNanoId(
27+
NanoIdUtils.DEFAULT_NUMBER_GENERATOR,
28+
NanoIdUtils.DEFAULT_ALPHABET,
29+
8
30+
).also { storage.set(PASSWORD, it) }
31+
1732
companion object {
1833
private const val ENABLED = "ENABLED"
1934

2035
private const val DEVICE_ID = "DEVICE_ID"
36+
private const val PORT = "PORT"
37+
private const val USERNAME = "USERNAME"
38+
private const val PASSWORD = "PASSWORD"
2139
}
2240
}

app/src/main/java/me/capcom/smsgateway/modules/localserver/WebService.kt

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import me.capcom.smsgateway.R
3737
import me.capcom.smsgateway.domain.EntitySource
3838
import me.capcom.smsgateway.domain.ProcessingState
3939
import me.capcom.smsgateway.extensions.configure
40-
import me.capcom.smsgateway.helpers.SettingsHelper
4140
import me.capcom.smsgateway.modules.health.HealthService
4241
import me.capcom.smsgateway.modules.health.domain.Status
4342
import me.capcom.smsgateway.modules.localserver.domain.Device
@@ -55,7 +54,7 @@ import kotlin.concurrent.thread
5554

5655
class WebService : Service() {
5756

58-
private val settingsHelper: SettingsHelper by inject()
57+
private val settings: LocalServerSettings by inject()
5958
private val messagesService: MessagesService by inject()
6059
private val notificationsService: NotificationsService by inject()
6160
private val healthService: HealthService by inject()
@@ -75,17 +74,20 @@ class WebService : Service() {
7574
private val server by lazy {
7675
embeddedServer(
7776
Netty,
78-
port = settingsHelper.serverPort,
77+
port = port,
7978
watchPaths = emptyList(),
8079
) {
8180
install(Authentication) {
8281
basic("auth-basic") {
8382
realm = "Access to SMS Gateway"
8483
validate { credentials ->
85-
if (credentials.name == "sms" && credentials.password == settingsHelper.serverToken) {
86-
UserIdPrincipal(credentials.name)
87-
} else {
88-
null
84+
when {
85+
credentials.name == username
86+
&& credentials.password == password -> UserIdPrincipal(
87+
credentials.name
88+
)
89+
90+
else -> null
8991
}
9092
}
9193
}
@@ -271,6 +273,10 @@ class WebService : Service() {
271273
}
272274
}
273275

276+
private val port = settings.port
277+
private val username = settings.username
278+
private val password = settings.password
279+
274280
override fun onCreate() {
275281
super.onCreate()
276282

@@ -287,7 +293,7 @@ class WebService : Service() {
287293
NotificationsService.NOTIFICATION_ID_LOCAL_SERVICE,
288294
getString(
289295
R.string.sms_gateway_is_running_on_port,
290-
settingsHelper.serverPort
296+
port
291297
)
292298
)
293299

app/src/main/java/me/capcom/smsgateway/ui/HomeFragment.kt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,6 @@ class HomeFragment : Fragment() {
7171
binding.textLocalUsername.movementMethod = LinkMovementMethod.getInstance()
7272
binding.textLocalPassword.movementMethod = LinkMovementMethod.getInstance()
7373

74-
binding.textLocalUsername.text = makeCopyableLink(
75-
Html.fromHtml(
76-
"<a href>sms</a>"
77-
)
78-
)
79-
binding.textLocalPassword.text = makeCopyableLink(
80-
Html.fromHtml(
81-
"<a href>${settingsHelper.serverToken}</a>"
82-
)
83-
)
84-
8574
binding.switchAutostart.isChecked = settingsHelper.autostart
8675

8776
binding.switchAutostart.setOnCheckedChangeListener { _, isChecked ->
@@ -132,13 +121,24 @@ class HomeFragment : Fragment() {
132121

133122
viewLifecycleOwner.lifecycleScope.launch {
134123
events.collect<IPReceivedEvent> { event ->
124+
binding.textLocalUsername.text = makeCopyableLink(
125+
Html.fromHtml(
126+
"<a href>${localServerSettings.username}</a>"
127+
)
128+
)
129+
binding.textLocalPassword.text = makeCopyableLink(
130+
Html.fromHtml(
131+
"<a href>${localServerSettings.password}</a>"
132+
)
133+
)
134+
135135
binding.textLocalIP.text = event.localIP?.let {
136136
makeCopyableLink(
137137
Html.fromHtml(
138138
getString(
139139
R.string.settings_local_address_is,
140140
event.localIP,
141-
settingsHelper.serverPort
141+
localServerSettings.port
142142
)
143143
)
144144
)
@@ -151,7 +151,7 @@ class HomeFragment : Fragment() {
151151
getString(
152152
R.string.settings_public_address_is,
153153
event.publicIP,
154-
settingsHelper.serverPort
154+
localServerSettings.port
155155
)
156156
)
157157
)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package me.capcom.smsgateway.ui.settings
2+
3+
import android.os.Bundle
4+
import android.text.InputType
5+
import android.util.TypedValue
6+
import android.view.View
7+
import android.widget.Toast
8+
import androidx.preference.EditTextPreference
9+
import androidx.preference.Preference
10+
import androidx.preference.PreferenceFragmentCompat
11+
import me.capcom.smsgateway.R
12+
13+
class LocalServerSettingsFragment : PreferenceFragmentCompat() {
14+
15+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
16+
super.onViewCreated(view, savedInstanceState)
17+
18+
val backgroundValue = TypedValue()
19+
requireContext().theme.resolveAttribute(
20+
android.R.attr.colorBackground,
21+
backgroundValue,
22+
true
23+
)
24+
25+
view.setBackgroundColor(backgroundValue.data)
26+
}
27+
28+
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
29+
setPreferencesFromResource(R.xml.local_server_preferences, rootKey)
30+
31+
findPreference<EditTextPreference>("localserver.PORT")?.setOnPreferenceChangeListener { _, newValue ->
32+
val value = newValue as? String
33+
val intValue = value?.toIntOrNull()
34+
if (intValue == null || intValue < 1024 || intValue > 65535) {
35+
showToast(
36+
getString(
37+
R.string.is_not_a_valid_port_must_be_between_1024_and_65535,
38+
value
39+
)
40+
)
41+
return@setOnPreferenceChangeListener false
42+
}
43+
44+
true
45+
}
46+
47+
findPreference<EditTextPreference>("localserver.USERNAME")?.setOnPreferenceChangeListener { _, newValue ->
48+
val value = newValue as? String
49+
if ((value?.length ?: 0) < 3) {
50+
showToast(getString(R.string.username_must_be_at_least_3_characters))
51+
return@setOnPreferenceChangeListener false
52+
}
53+
54+
true
55+
}
56+
findPreference<EditTextPreference>("localserver.PASSWORD")?.setOnPreferenceChangeListener { _, newValue ->
57+
val value = newValue as? String
58+
if ((value?.length ?: 0) < 8) {
59+
showToast(getString(R.string.password_must_be_at_least_8_characters))
60+
return@setOnPreferenceChangeListener false
61+
}
62+
63+
true
64+
}
65+
}
66+
67+
override fun onDisplayPreferenceDialog(preference: Preference) {
68+
if (preference.key == "localserver.PORT"
69+
) {
70+
(preference as EditTextPreference).setOnBindEditTextListener {
71+
it.inputType = InputType.TYPE_CLASS_NUMBER
72+
it.setSelectAllOnFocus(true)
73+
it.selectAll()
74+
}
75+
}
76+
77+
if (preference.key == "localserver.PASSWORD"
78+
|| preference.key == "localserver.USERNAME"
79+
) {
80+
(preference as EditTextPreference).setOnBindEditTextListener {
81+
it.inputType = InputType.TYPE_CLASS_TEXT
82+
it.setSelectAllOnFocus(true)
83+
it.selectAll()
84+
}
85+
}
86+
87+
super.onDisplayPreferenceDialog(preference)
88+
}
89+
90+
private fun showToast(message: String) {
91+
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
92+
}
93+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:tint="#000000"
5+
android:viewportWidth="24"
6+
android:viewportHeight="24">
7+
8+
<path
9+
android:fillColor="@android:color/white"
10+
android:pathData="M2,17h20v2H2V17zM3.15,12.95L4,11.47l0.85,1.48l1.3,-0.75L5.3,10.72H7v-1.5H5.3l0.85,-1.47L4.85,7L4,8.47L3.15,7l-1.3,0.75L2.7,9.22H1v1.5h1.7L1.85,12.2L3.15,12.95zM9.85,12.2l1.3,0.75L12,11.47l0.85,1.48l1.3,-0.75l-0.85,-1.48H15v-1.5h-1.7l0.85,-1.47L12.85,7L12,8.47L11.15,7l-1.3,0.75l0.85,1.47H9v1.5h1.7L9.85,12.2zM23,9.22h-1.7l0.85,-1.47L20.85,7L20,8.47L19.15,7l-1.3,0.75l0.85,1.47H17v1.5h1.7l-0.85,1.48l1.3,0.75L20,11.47l0.85,1.48l1.3,-0.75l-0.85,-1.48H23V9.22z" />
11+
12+
</vector>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:tint="#000000"
5+
android:viewportWidth="24"
6+
android:viewportHeight="24">
7+
8+
<path
9+
android:fillColor="@android:color/white"
10+
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
11+
12+
</vector>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M2,17h20v2H2V17zM3.15,12.95L4,11.47l0.85,1.48l1.3,-0.75L5.3,10.72H7v-1.5H5.3l0.85,-1.47L4.85,7L4,8.47L3.15,7l-1.3,0.75L2.7,9.22H1v1.5h1.7L1.85,12.2L3.15,12.95zM9.85,12.2l1.3,0.75L12,11.47l0.85,1.48l1.3,-0.75l-0.85,-1.48H15v-1.5h-1.7l0.85,-1.47L12.85,7L12,8.47L11.15,7l-1.3,0.75l0.85,1.47H9v1.5h1.7L9.85,12.2zM23,9.22h-1.7l0.85,-1.47L20.85,7L20,8.47L19.15,7l-1.3,0.75l0.85,1.47H17v1.5h1.7l-0.85,1.48l1.3,0.75L20,11.47l0.85,1.48l1.3,-0.75l-0.85,-1.48H23V9.22z" />
10+
11+
</vector>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
10+
11+
</vector>

app/src/main/res/layout/fragment_settings.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
android:layout_height="wrap_content"
7272
android:layout_gravity="end"
7373
android:layout_margin="4dp"
74-
android:text="@string/username" />
74+
android:text="@string/label_username" />
7575

7676
<TextView
7777
android:id="@+id/textLocalUsername"
@@ -87,7 +87,7 @@
8787
android:layout_height="wrap_content"
8888
android:layout_gravity="end"
8989
android:layout_margin="4dp"
90-
android:text="@string/password" />
90+
android:text="@string/label_password" />
9191

9292
<TextView
9393
android:id="@+id/textLocalPassword"
@@ -137,7 +137,7 @@
137137
android:layout_height="wrap_content"
138138
android:layout_gravity="end"
139139
android:layout_margin="4dp"
140-
android:text="@string/username" />
140+
android:text="@string/label_username" />
141141

142142
<TextView
143143
android:id="@+id/textRemoteUsername"
@@ -152,7 +152,7 @@
152152
android:layout_height="wrap_content"
153153
android:layout_gravity="end"
154154
android:layout_margin="4dp"
155-
android:text="@string/password" />
155+
android:text="@string/label_password" />
156156

157157
<TextView
158158
android:id="@+id/textRemotePassword"

0 commit comments

Comments
 (0)