Merge pull request #470 from FineFindus/feat/tracking-urls

feat: remove tracking parameter from URLs
This commit is contained in:
LucasGGamerM
2024-07-24 15:33:17 -03:00
committed by GitHub
7 changed files with 133 additions and 2 deletions

View File

@@ -80,6 +80,7 @@ public class GlobalUserPreferences{
public static boolean mentionRebloggerAutomatically;
public static boolean showPostsWithoutAlt;
public static boolean showMediaPreview;
public static boolean removeTrackingParams;
public static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
@@ -160,6 +161,7 @@ public class GlobalUserPreferences{
mentionRebloggerAutomatically=prefs.getBoolean("mentionRebloggerAutomatically", false);
showPostsWithoutAlt=prefs.getBoolean("showPostsWithoutAlt", true);
showMediaPreview=prefs.getBoolean("showMediaPreview", true);
removeTrackingParams=prefs.getBoolean("removeTrackingParams", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
@@ -234,6 +236,7 @@ public class GlobalUserPreferences{
.putBoolean("enableDeleteNotifications", enableDeleteNotifications)
.putBoolean("showPostsWithoutAlt", showPostsWithoutAlt)
.putBoolean("showMediaPreview", showMediaPreview)
.putBoolean("removeTrackingParams", removeTrackingParams)
.apply();
}

View File

@@ -99,6 +99,7 @@ import org.joinmastodon.android.ui.text.ComposeAutocompleteSpan;
import org.joinmastodon.android.ui.text.ComposeHashtagOrMentionSpan;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
import org.joinmastodon.android.utils.Tracking;
import org.joinmastodon.android.utils.TransferSpeedTracker;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.viewcontrollers.ComposeAutocompleteViewController;
@@ -1175,6 +1176,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private void actuallyPublish(boolean preview){
String text=mainEditText.getText().toString();
if(GlobalUserPreferences.removeTrackingParams)
text=Tracking.cleanUrlsInText(text);
CreateStatus.Request req=new CreateStatus.Request();
if("bottom".equals(postLang.encoding)){
text=new StatusTextEncoder(Bottom::encode).encode(text);

View File

@@ -25,7 +25,7 @@ public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
private Instance instance;
//MOSHIDON
private CheckableListItem<Void> unlistedRepliesItem;
private CheckableListItem<Void> unlistedRepliesItem, removeTrackingParams;
@Override
@@ -38,7 +38,8 @@ public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
privacy=self.source.privacy;
onDataLoaded(List.of(
privacyItem=new ListItem<>(R.string.sk_settings_default_visibility, getPrivacyString(privacy), R.drawable.ic_fluent_eye_24_regular, this::onPrivacyClick, 0, false),
unlistedRepliesItem=new CheckableListItem<>(R.string.mo_change_default_reply_visibility_to_unlisted, R.string.mo_setting_default_reply_privacy_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.defaultToUnlistedReplies, R.drawable.ic_fluent_lock_open_24_regular, i->toggleCheckableItem(unlistedRepliesItem), true),
unlistedRepliesItem=new CheckableListItem<>(R.string.mo_change_default_reply_visibility_to_unlisted, R.string.mo_setting_default_reply_privacy_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.defaultToUnlistedReplies, R.drawable.ic_fluent_lock_open_24_regular, i->toggleCheckableItem(unlistedRepliesItem)),
removeTrackingParams=new CheckableListItem<>(R.string.mo_settings_remove_tracking_params, R.string.mo_settings_remove_tracking_params_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.removeTrackingParams, R.drawable.ic_fluent_eye_tracking_off_24_filled, i->toggleCheckableItem(removeTrackingParams), true),
lockedItem=new CheckableListItem<>(R.string.sk_settings_lock_account, 0, CheckableListItem.Style.SWITCH, self.locked, R.drawable.ic_fluent_person_available_24_regular, i->toggleCheckableItem(lockedItem))
));
@@ -89,6 +90,7 @@ public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
public void onPause(){
super.onPause();
GlobalUserPreferences.defaultToUnlistedReplies=unlistedRepliesItem.checked;
GlobalUserPreferences.removeTrackingParams=removeTrackingParams.checked;
GlobalUserPreferences.save();
AccountSession s=AccountSessionManager.get(accountID);
Account self=s.self;

View File

@@ -125,6 +125,7 @@ import org.joinmastodon.android.ui.sheets.BlockAccountConfirmationSheet;
import org.joinmastodon.android.ui.sheets.MuteAccountConfirmationSheet;
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.utils.Tracking;
import org.parceler.Parcels;
import java.io.File;
@@ -196,6 +197,8 @@ public class UiUtils {
}
public static void launchWebBrowser(Context context, String url) {
if(GlobalUserPreferences.removeTrackingParams)
url=Tracking.removeTrackingParameters(url);
try {
if (GlobalUserPreferences.useCustomTabs) {
new CustomTabsIntent.Builder()
@@ -1480,6 +1483,8 @@ public class UiUtils {
}
public static void copyText(View v, String text) {
if(GlobalUserPreferences.removeTrackingParams)
text=Tracking.cleanUrlsInText(text);
Context context = v.getContext();
context.getSystemService(ClipboardManager.class).setPrimaryClip(ClipData.newPlainText(null, text));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || UiUtils.isMIUI()) { // Android 13+ SystemUI shows its own thing when you put things into the clipboard

View File

@@ -0,0 +1,107 @@
package org.joinmastodon.android.utils;
import android.net.Uri;
import android.util.Patterns;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.regex.Matcher;
// Inspired by https://github.com/GeopJr/Tuba/blob/91a036edff9ab1ffb38d5b54a33023e5db551051/src/Utils/Tracking.vala
public class Tracking{
/* https://github.com/brave/brave-core/blob/face8d58ab81422480c8c05b9ba5d518e1a2d227/components/query_filter/utils.cc#L23-L119 */
private static final String[] TRACKING_IDS={
// Strip any utm_ based ones
"utm_",
// https://github.com/brave/brave-browser/issues/4239
"fbclid", "gclid", "msclkid", "mc_eid",
// New Facebook one
"mibexid",
// https://github.com/brave/brave-browser/issues/9879
"dclid",
// https://github.com/brave/brave-browser/issues/13644
"oly_anon_id", "oly_enc_id",
// https://github.com/brave/brave-browser/issues/11579
"_openstat",
// https://github.com/brave/brave-browser/issues/11817
"vero_conv", "vero_id",
// https://github.com/brave/brave-browser/issues/13647
"wickedid",
// https://github.com/brave/brave-browser/issues/11578
"yclid",
// https://github.com/brave/brave-browser/issues/8975
"__s",
// https://github.com/brave/brave-browser/issues/17451
"rb_clickid",
// https://github.com/brave/brave-browser/issues/17452
"s_cid",
// https://github.com/brave/brave-browser/issues/17507
"ml_subscriber", "ml_subscriber_hash",
// https://github.com/brave/brave-browser/issues/18020
"twclid",
// https://github.com/brave/brave-browser/issues/18758
"gbraid", "wbraid",
// https://github.com/brave/brave-browser/issues/9019
"_hsenc", "__hssc", "__hstc", "__hsfp", "hsCtaTracking",
// https://github.com/brave/brave-browser/issues/22082
"oft_id", "oft_k", "oft_lk", "oft_d", "oft_c", "oft_ck", "oft_ids", "oft_sk",
// https://github.com/brave/brave-browser/issues/11580
"igshid",
// Instagram Threads
"ad_id", "adset_id", "campaign_id", "ad_name", "adset_name", "campaign_name", "placement",
// Reddit
"share_id", "ref", "ref_share",
};
/**
* Tries to remove tracking parameters from a URL.
*
* @param url The original URL with tracking parameters
* @return The URL with the tracking parameters removed.
*/
@NonNull
public static String removeTrackingParameters(@NonNull String url){
Uri uri=Uri.parse(url);
if(uri==null)
return url;
Uri.Builder uriBuilder=uri.buildUpon().clearQuery();
// Iterate over existing parameters and add them back if they are not tracking parameters
for(String paramName : uri.getQueryParameterNames()){
if(!isTrackingParameter(paramName)){
for(String paramValue : uri.getQueryParameters(paramName)){
uriBuilder.appendQueryParameter(paramName, paramValue);
}
}
}
return uriBuilder.build().toString();
}
/**
* Cleans URLs within the provided text, removing the tracking parameters from them.
*
* @param text The text that may contain URLs.
* @return The given text with cleaned URLs.
*/
public static String cleanUrlsInText(String text){
Matcher matcher=Patterns.WEB_URL.matcher(text);
StringBuffer sb=new StringBuffer();
while(matcher.find()){
String url=matcher.group();
matcher.appendReplacement(sb, removeTrackingParameters(url));
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* Returns true if the given parameter is used for tracking.
*/
private static boolean isTrackingParameter(String parameter){
return Arrays.stream(TRACKING_IDS).anyMatch(trackingId->parameter.toLowerCase().contains(trackingId));
}
}