background service support for custom headers

- Adds zrok interstitial header skip
This commit is contained in:
zlshames
2024-11-13 11:58:55 -05:00
parent 6957dc149d
commit 2e00cc68f4
5 changed files with 67 additions and 10 deletions

View File

@ -20,6 +20,7 @@ import io.socket.client.Socket
import java.net.URISyntaxException
import java.net.URLEncoder
import org.json.JSONObject
import java.util.Collections.singletonList
class SocketIOForegroundService : Service() {
@ -63,6 +64,7 @@ class SocketIOForegroundService : Service() {
val serverUrl: String? = prefs.getString("flutter.serverAddress", null)
val keepAppAlive: Boolean = prefs.getBoolean("flutter.keepAppAlive", false)
val storedPassword: String? = prefs.getString("flutter.guidAuthKey", null)
val customHeaders: String? = prefs.getString("flutter.customHeaders", null)
// Make sure the user has enabled the service
if (!keepAppAlive) {
@ -100,6 +102,25 @@ class SocketIOForegroundService : Service() {
Log.d(Constants.logTag, "Foreground Service is connecting to: $serverUrl")
val opts = IO.Options()
try {
// Read the custom headers JSON string from preferences and parse it into a map
val extraHeaders = mutableMapOf<String, List<String>>()
val customHeaderMap = JSONObject(customHeaders)
customHeaderMap.keys().forEach { key ->
// Add the key-value pair to extraHeaders
extraHeaders[key] = singletonList(customHeaderMap.getString(key))
}
opts.extraHeaders = extraHeaders
} catch (e: Exception) {
Log.e(Constants.logTag, "Failed to parse custom headers JSON string!", e)
}
// Only log the headers if they are not null or empty
if (opts.extraHeaders != null && opts.extraHeaders.isNotEmpty()) {
Log.d(Constants.logTag, "Socket.io Custom headers: ${opts.extraHeaders}")
}
val encodedPw = URLEncoder.encode(storedPassword, "UTF-8")
opts.query = "password=$encodedPw"
mSocket = IO.socket(serverUrl, opts)

View File

@ -53,6 +53,13 @@ Future<DateTime?> showTimeframePicker(String title, BuildContext context,
icon = Icons.calendar_view_month;
}
String dateStr;
if (tmpDate.isToday()) {
dateStr = buildTime(tmpDate);
} else {
dateStr = buildFullDate(tmpDate, includeTime: tmpDate.isToday(), useTodayYesterday: useTodayYesterday);
}
return InkWell(
onTap: () {
finalDate = tmpDate;
@ -82,8 +89,8 @@ Future<DateTime?> showTimeframePicker(String title, BuildContext context,
Container(
constraints: const BoxConstraints(minWidth: 20),
),
Text(buildFullDate(tmpDate, includeTime: tmpDate.isToday(), useTodayYesterday: useTodayYesterday),
style: context.theme.textTheme.bodyLarge!.copyWith(color: context.theme.colorScheme.secondary)),
Text(dateStr,
style: context.theme.textTheme.bodyLarge!.copyWith(color: context.theme.colorScheme.secondary), overflow: TextOverflow.fade),
],
)));
}).toList();

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:bluebubbles/helpers/helpers.dart';
import 'package:bluebubbles/services/services.dart';
import 'package:collection/collection.dart';
@ -5,7 +7,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
Future<bool> showCustomHeadersDialog(BuildContext context) async {
int headers = ss.settings.customHeaders.length.clamp(1, 100);
RxInt headers = ss.settings.customHeaders.length.clamp(0, 100).obs;
List<TextEditingController> keyControllers = [];
List<TextEditingController> valueControllers = [];
if (ss.settings.customHeaders.isNotEmpty) {
@ -34,15 +36,17 @@ Future<bool> showCustomHeadersDialog(BuildContext context) async {
constraints: BoxConstraints(
maxHeight: context.mediaQuery.size.height * 0.2,
),
child: ListView.builder(
child: Obx(() {
return ListView.builder(
shrinkWrap: true,
itemCount: headers,
itemCount: headers.value,
findChildIndexCallback: (key) => findChildIndexByKey(ss.settings.customHeaders.keys.toList(), key, (item) => item),
itemBuilder: (context, index) {
return Row(
key: ValueKey(ss.settings.customHeaders.keys.toList()[index]),
key: ValueKey(index),
children: [
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
@ -55,9 +59,9 @@ Future<bool> showCustomHeadersDialog(BuildContext context) async {
),
),
Flexible(
flex: 2,
flex: 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.only(left: 8, top: 8, bottom: 8),
child: TextField(
controller: valueControllers[index],
decoration: const InputDecoration(
@ -67,9 +71,20 @@ Future<bool> showCustomHeadersDialog(BuildContext context) async {
),
),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
keyControllers.removeAt(index);
valueControllers.removeAt(index);
setState(() {
headers.value -= 1;
});
},
),
]
);
},
);}
),
),
const SizedBox(height: 5),
@ -78,7 +93,7 @@ Future<bool> showCustomHeadersDialog(BuildContext context) async {
keyControllers.add(TextEditingController());
valueControllers.add(TextEditingController());
setState(() {
headers++;
headers.value += 1;
});
},
icon: const Icon(
@ -110,8 +125,10 @@ Future<bool> showCustomHeadersDialog(BuildContext context) async {
map.addEntries([MapEntry(keyController.text, valueController.text)]);
}
});
ss.settings.customHeaders.value = map;
await ss.settings.saveOne('customHeaders');
await ss.prefs.setString('customHeaders', jsonEncode(http.headers));
http.onInit();
Navigator.of(context).pop(true);
}

View File

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:io';
import 'package:bluebubbles/app/layouts/settings/pages/advanced/firebase_panel.dart';
@ -124,6 +125,9 @@ class _NotificationProvidersState extends OptimizedState<NotificationProvidersPa
ss.settings.keepAppAlive.value = val;
await ss.saveSettings(ss.settings);
// Save the custom headers to prefs
await ss.prefs.setString('customHeaders', jsonEncode(http.headers));
// We don't need to start the service here because it will be started
// when the app is inactive.
if (!val) {

View File

@ -59,7 +59,15 @@ class HttpService extends GetxService {
}
}
Map<String, String> get headers => ss.settings.customHeaders..addAll({'ngrok-skip-browser-warning': 'true'});
Map<String, String> get headers {
if (ss.settings.serverAddress.contains('ngrok')) {
ss.settings.customHeaders.addAll({'ngrok-skip-browser-warning': 'true'});
} else if (ss.settings.serverAddress.contains('zrok')) {
ss.settings.customHeaders.addAll({'skip_zrok_interstitial': 'true'});
}
return ss.settings.customHeaders;
}
/// Initialize dio with a couple options and intercept all requests for logging
@override