mirror of
https://github.com/BlueBubblesApp/bluebubbles-app.git
synced 2025-05-17 05:05:57 +08:00
background service support for custom headers
- Adds zrok interstitial header skip
This commit is contained in:
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user