From e8711379d0a11567ffe2d27e2e3325b12041090d Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 11 Jan 2021 16:37:34 -0500 Subject: [PATCH] the great user agent change --- app/build.gradle | 4 +- .../instagrabber/InstaGrabberApplication.java | 12 +++ .../asyncs/CreateThreadAction.java | 2 +- .../asyncs/GetActivityAsyncTask.java | 3 +- .../instagrabber/asyncs/UsernameFetcher.java | 3 +- .../fragments/HashTagFragment.java | 5 +- .../repositories/FriendshipRepository.java | 10 +-- .../repositories/NewsRepository.java | 10 +-- .../repositories/StoriesRepository.java | 5 +- .../awais/instagrabber/utils/Constants.java | 12 ++- .../instagrabber/utils/ExportImportUtils.java | 4 + .../awais/instagrabber/utils/FlavorTown.java | 8 ++ .../awais/instagrabber/utils/LocaleUtils.java | 14 ++-- .../instagrabber/utils/SettingsHelper.java | 17 ++-- .../instagrabber/utils/UpdateChecker.java | 2 +- .../instagrabber/utils/UserAgentUtils.java | 77 +++++++++++++++++++ .../webservices/AddCookiesInterceptor.java | 2 +- .../webservices/FriendshipService.java | 10 +-- .../instagrabber/webservices/NewsService.java | 10 ++- .../webservices/StoriesService.java | 4 +- .../instagrabber/webservices/TagsService.java | 14 ++-- 21 files changed, 163 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java diff --git a/app/build.gradle b/app/build.gradle index 66aab6cf..8083b4e2 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { minSdkVersion 21 targetSdkVersion 29 - versionCode 57 - versionName '19.0.5' + versionCode 58 + versionName '19.1.0' multiDexEnabled true diff --git a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java index c5cd0d69..4bd2dc7a 100644 --- a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java +++ b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java @@ -11,12 +11,14 @@ import com.facebook.imagepipeline.core.ImagePipelineConfig; import java.net.CookieHandler; import java.text.SimpleDateFormat; +import java.util.concurrent.ThreadLocalRandom; import java.util.UUID; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.LocaleUtils; import awais.instagrabber.utils.SettingsHelper; import awais.instagrabber.utils.TextUtils; +import awais.instagrabber.utils.UserAgentUtils; import awaisomereport.CrashReporter; import awaisomereport.LogCollector; @@ -85,5 +87,15 @@ public final class InstaGrabberApplication extends Application { if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) { settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString()); } + + if (settingsHelper.getInteger(Constants.BROWSER_UA_CODE) == -1) { + int randomNum = ThreadLocalRandom.current().nextInt(0, UserAgentUtils.browsers.length); + settingsHelper.putInteger(Constants.BROWSER_UA_CODE, randomNum); + } + + if (settingsHelper.getInteger(Constants.APP_UA_CODE) == -1) { + int randomNum = ThreadLocalRandom.current().nextInt(0, UserAgentUtils.devices.length); + settingsHelper.putInteger(Constants.APP_UA_CODE, randomNum); + } } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/asyncs/CreateThreadAction.java b/app/src/main/java/awais/instagrabber/asyncs/CreateThreadAction.java index 74a24496..a38eee76 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/CreateThreadAction.java +++ b/app/src/main/java/awais/instagrabber/asyncs/CreateThreadAction.java @@ -35,7 +35,7 @@ public class CreateThreadAction extends AsyncTask { try { urlConnection = (HttpURLConnection) new URL(url).openConnection(); urlConnection.setRequestMethod("POST"); - urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); + urlConnection.setRequestProperty("User-Agent", Utils.settingsHelper.getString(Constants.APP_UA)); urlConnection.setUseCaches(false); final String urlParameters = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] + "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie) diff --git a/app/src/main/java/awais/instagrabber/asyncs/GetActivityAsyncTask.java b/app/src/main/java/awais/instagrabber/asyncs/GetActivityAsyncTask.java index 9d8ca49c..13a88ee4 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/GetActivityAsyncTask.java +++ b/app/src/main/java/awais/instagrabber/asyncs/GetActivityAsyncTask.java @@ -14,6 +14,7 @@ import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.NetworkUtils; import awais.instagrabber.utils.TextUtils; +import awais.instagrabber.utils.Utils; public class GetActivityAsyncTask extends AsyncTask { private static final String TAG = "GetActivityAsyncTask"; @@ -44,7 +45,7 @@ public class GetActivityAsyncTask extends AsyncTask { private final FetchListener fetchListener; @@ -31,7 +32,7 @@ public final class UsernameFetcher extends AsyncTask { try { final HttpURLConnection conn = (HttpURLConnection) new URL("https://i.instagram.com/api/v1/users/" + uid + "/info/").openConnection(); - conn.setRequestProperty("User-Agent", Constants.USER_AGENT); + conn.setRequestProperty("User-Agent", Utils.settingsHelper.getString(Constants.BROWSER_UA)); conn.setUseCaches(true); final JSONObject user; diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 366eaf35..ce3b1cf9 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -414,10 +414,11 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe hashtagDetailsBinding.btnFollowTag.setOnClickListener(v -> { final String cookie = settingsHelper.getString(Constants.COOKIE); final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); + final String ua = settingsHelper.getString(Constants.BROWSER_UA); if (csrfToken != null) { hashtagDetailsBinding.btnFollowTag.setClickable(false); if (!hashtagModel.getFollowing()) { - tagsService.follow(hashtag.substring(1), csrfToken, new ServiceCallback() { + tagsService.follow(ua, hashtag.substring(1), csrfToken, new ServiceCallback() { @Override public void onSuccess(final Boolean result) { hashtagDetailsBinding.btnFollowTag.setClickable(true); @@ -445,7 +446,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe }); return; } - tagsService.unfollow(hashtag.substring(1), csrfToken, new ServiceCallback() { + tagsService.unfollow(ua, hashtag.substring(1), csrfToken, new ServiceCallback() { @Override public void onSuccess(final Boolean result) { hashtagDetailsBinding.btnFollowTag.setClickable(true); diff --git a/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.java b/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.java index 919efaaa..123a7a4d 100644 --- a/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/FriendshipRepository.java @@ -8,7 +8,6 @@ import retrofit2.Call; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; -import retrofit2.http.Header; import retrofit2.http.POST; import retrofit2.http.Path; import retrofit2.http.QueryMap; @@ -17,20 +16,17 @@ public interface FriendshipRepository { @FormUrlEncoded @POST("/api/v1/friendships/{action}/{id}/") - Call change(@Header("User-Agent") String userAgent, - @Path("action") String action, + Call change(@Path("action") String action, @Path("id") long id, @FieldMap Map form); @FormUrlEncoded @POST("/api/v1/restrict_action/{action}/") - Call toggleRestrict(@Header("User-Agent") String userAgent, - @Path("action") String action, + Call toggleRestrict(@Path("action") String action, @FieldMap Map form); @GET("/api/v1/friendships/{userId}/{type}/") - Call getList(@Header("User-Agent") String userAgent, - @Path("userId") long userId, + Call getList(@Path("userId") long userId, @Path("type") String type, // following or followers @QueryMap(encoded = true) Map queryParams); } diff --git a/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java b/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java index 20b50934..fe6bdb4f 100644 --- a/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java @@ -3,6 +3,7 @@ package awais.instagrabber.repositories; import java.util.Map; import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; @@ -14,16 +15,13 @@ import retrofit2.http.Query; public interface NewsRepository { - @Headers("User-Agent: " + Constants.USER_AGENT) @GET("https://www.instagram.com/accounts/activity/?__a=1") - Call webInbox(); + Call webInbox(@Header("User-Agent") String userAgent); - @Headers("User-Agent: " + Constants.I_USER_AGENT) @GET("/api/v1/news/inbox/") - Call appInbox(@Query(value = "mark_as_seen", encoded = true) boolean markAsSeen); + Call appInbox(@Header("User-Agent") String userAgent, @Query(value = "mark_as_seen", encoded = true) boolean markAsSeen); @FormUrlEncoded - @Headers("User-Agent: " + Constants.I_USER_AGENT) @POST("/api/v1/discover/ayml/") - Call getAyml(@FieldMap final Map form); + Call getAyml(@Header("User-Agent") String userAgent, @FieldMap final Map form); } diff --git a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java index 17af1b86..5becfc5b 100644 --- a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java @@ -28,12 +28,11 @@ public interface StoriesRepository { Call fetchArchive(@QueryMap Map queryParams); @GET - Call getUserStory(@Header("User-Agent") String userAgent, @Url String url); + Call getUserStory(@Url String url); @FormUrlEncoded @POST("/api/v1/media/{storyId}/{stickerId}/{action}/") - Call respondToSticker(@Header("User-Agent") String userAgent, - @Path("storyId") String storyId, + Call respondToSticker(@Path("storyId") String storyId, @Path("stickerId") String stickerId, @Path("action") String action, // story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index 51fcf220..64beacb6 100644 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -9,8 +9,10 @@ public final class Constants { public static final String APP_THEME = "app_theme_v19"; public static final String APP_LANGUAGE = "app_language_v19"; public static final String STORY_SORT = "story_sort"; - // int prefs + // int prefs, do not export public static final String PREV_INSTALL_VERSION = "prevVersion"; + public static final String BROWSER_UA_CODE = "browser_ua_code"; + public static final String APP_UA_CODE = "app_ua_code"; // boolean prefs public static final String DOWNLOAD_USER_FOLDER = "download_user_folder"; // deprecated: public static final String BOTTOM_TOOLBAR = "bottom_toolbar"; @@ -31,6 +33,8 @@ public final class Constants { public static final String COOKIE = "cookie"; public static final String SHOW_QUICK_ACCESS_DIALOG = "show_quick_dlg"; public static final String DEVICE_UUID = "device_uuid"; + public static final String BROWSER_UA = "browser_ua"; + public static final String APP_UA = "app_ua"; //////////////////////// EXTRAS //////////////////////// public static final String EXTRAS_USER = "user"; public static final String EXTRAS_HASHTAG = "hashtag"; @@ -54,12 +58,6 @@ public final class Constants { // Notification ids public static final int ACTIVITY_NOTIFICATION_ID = 10; - // spoof - public static final String USER_AGENT = "Mozilla/5.0 (Linux; Android 8.1.0; motorola one Build/OPKS28.63-18-3; wv) " + - "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.80 Mobile Safari/537.36"; - public static final String I_USER_AGENT = - "Instagram 169.3.0.30.135 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 264009054)"; - public static final String A_USER_AGENT = "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me"; // see https://github.com/dilame/instagram-private-api/blob/master/src/core/constants.ts public static final String SUPPORTED_CAPABILITIES = "[ { \"name\": \"SUPPORTED_SDK_VERSIONS\", \"value\":" + " \"13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0," + diff --git a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java index 03003ce0..e94f71c7 100755 --- a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java @@ -343,6 +343,10 @@ public final class ExportImportUtils { jsonObject.remove(Constants.COOKIE); jsonObject.remove(Constants.DEVICE_UUID); jsonObject.remove(Constants.PREV_INSTALL_VERSION); + jsonObject.remove(Constants.BROWSER_UA_CODE); + jsonObject.remove(Constants.BROWSER_UA); + jsonObject.remove(Constants.APP_UA_CODE); + jsonObject.remove(Constants.APP_UA); return jsonObject; } catch (Exception e) { Log.e(TAG, "Error exporting settings", e); diff --git a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java index 1559afcd..b63620ae 100755 --- a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java +++ b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java @@ -102,6 +102,14 @@ public final class FlavorTown { public static void changelogCheck(@NonNull final Context context) { if (settingsHelper.getInteger(Constants.PREV_INSTALL_VERSION) < BuildConfig.VERSION_CODE) { + final String langCode = settingsHelper.getString(Constants.APP_LANGUAGE); + final String lang = LocaleUtils.getCorrespondingLanguageCode(langCode); + final int appUaCode = settingsHelper.getInteger(Constants.APP_UA_CODE); + final String appUa = UserAgentUtils.generateAppUA(appUaCode, lang); + settingsHelper.putString(Constants.APP_UA, appUa); + final int browserUaCode = settingsHelper.getInteger(Constants.BROWSER_UA_CODE); + final String browserUa = UserAgentUtils.generateBrowserUA(browserUaCode); + settingsHelper.putString(Constants.BROWSER_UA, browserUa); Toast.makeText(context, R.string.updated, Toast.LENGTH_SHORT).show(); settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE); } diff --git a/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java b/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java index 0ea69a55..c48b3341 100755 --- a/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java @@ -19,7 +19,11 @@ public final class LocaleUtils { if (baseContext instanceof ContextThemeWrapper) baseContext = ((ContextThemeWrapper) baseContext).getBaseContext(); - final String lang = LocaleUtils.getCorrespondingLanguageCode(baseContext); + if (Utils.settingsHelper == null) + Utils.settingsHelper = new SettingsHelper(baseContext); + + final String appLanguageSettings = Utils.settingsHelper.getString(Constants.APP_LANGUAGE); + final String lang = TextUtils.isEmpty(appLanguageSettings) ? null : LocaleUtils.getCorrespondingLanguageCode(appLanguageSettings); currentLocale = TextUtils.isEmpty(lang) ? defaultLocale : (lang.contains("_") ? new Locale(lang.split("_")[0], lang.split("_")[1]) : new Locale(lang)); @@ -49,13 +53,7 @@ public final class LocaleUtils { } @Nullable - private static String getCorrespondingLanguageCode(final Context baseContext) { - if (Utils.settingsHelper == null) - Utils.settingsHelper = new SettingsHelper(baseContext); - - final String appLanguageSettings = Utils.settingsHelper.getString(Constants.APP_LANGUAGE); - if (TextUtils.isEmpty(appLanguageSettings)) return null; - + public static String getCorrespondingLanguageCode(final String appLanguageSettings) { final int appLanguageIndex = Integer.parseInt(appLanguageSettings); if (appLanguageIndex == 1) return "en"; if (appLanguageIndex == 2) return "fr"; diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java index da393e61..285485d4 100755 --- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java +++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java @@ -9,8 +9,12 @@ import androidx.annotation.StringDef; import androidx.appcompat.app.AppCompatDelegate; import static awais.instagrabber.utils.Constants.APP_LANGUAGE; +import static awais.instagrabber.utils.Constants.APP_UA; +import static awais.instagrabber.utils.Constants.APP_UA_CODE; import static awais.instagrabber.utils.Constants.APP_THEME; import static awais.instagrabber.utils.Constants.AUTOPLAY_VIDEOS; +import static awais.instagrabber.utils.Constants.BROWSER_UA; +import static awais.instagrabber.utils.Constants.BROWSER_UA_CODE; import static awais.instagrabber.utils.Constants.CHECK_ACTIVITY; import static awais.instagrabber.utils.Constants.CHECK_UPDATES; import static awais.instagrabber.utils.Constants.COOKIE; @@ -79,7 +83,7 @@ public final class SettingsHelper { private int getIntegerDefault(@IntegerSettings final String key) { if (APP_THEME.equals(key)) return getThemeCode(true); - if (PREV_INSTALL_VERSION.equals(key)) return -1; + if (PREV_INSTALL_VERSION.equals(key) || APP_UA_CODE.equals(key) || BROWSER_UA_CODE.equals(key)) return -1; return 0; } @@ -120,10 +124,11 @@ public final class SettingsHelper { } @StringDef( - {APP_LANGUAGE, APP_THEME, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT, - DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME, PREF_POSTS_LAYOUT, - PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT, PREF_LOCATION_POSTS_LAYOUT, - PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT, STORY_SORT, PREF_EMOJI_VARIANTS}) + {APP_LANGUAGE, APP_THEME, APP_UA, BROWSER_UA, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, + CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME, + PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT, + PREF_LOCATION_POSTS_LAYOUT, PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT, + STORY_SORT, PREF_EMOJI_VARIANTS}) public @interface StringSettings {} @StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, @@ -131,6 +136,6 @@ public final class SettingsHelper { CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED}) public @interface BooleanSettings {} - @StringDef({PREV_INSTALL_VERSION}) + @StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE}) public @interface IntegerSettings {} } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java b/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java index ea39e370..3ea67ba1 100755 --- a/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java +++ b/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java @@ -30,7 +30,7 @@ public final class UpdateChecker extends AsyncTask { HttpURLConnection conn = (HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection(); conn.setUseCaches(false); - conn.setRequestProperty("User-Agent", Constants.A_USER_AGENT); + conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me"); conn.connect(); final int responseCode = conn.getResponseCode(); diff --git a/app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java b/app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java new file mode 100644 index 00000000..36944cce --- /dev/null +++ b/app/src/main/java/awais/instagrabber/utils/UserAgentUtils.java @@ -0,0 +1,77 @@ +package awais.instagrabber.utils; + +import androidx.annotation.NonNull; + +public class UserAgentUtils { + + /* GraphQL user agents (which are just standard browser UA's). + * Go to https://www.whatismybrowser.com/guides/the-latest-user-agent/ to update it + * Windows first (Assume win64 not wow64): Chrome, Firefox, Edge + * Then macOS: Chrome, Firefox, Safari + */ + public static final String[] browsers = { + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 11.1; rv:84.0) Gecko/20100101 Firefox/84.0", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15" + }; + // use APKpure, assume x86 + private static final String igVersion = "169.3.0.30.135"; + private static final String igVersionCode = "264009054"; + // https://github.com/dilame/instagram-private-api/blob/master/src/samples/devices.json + // presumed constant, so no need to update + public static final String[] devices = { + "25/7.1.1; 440dpi; 1080x1920; Xiaomi; Mi Note 3; jason; qcom", + "23/6.0.1; 480dpi; 1080x1920; Xiaomi; Redmi Note 3; kenzo; qcom", + "23/6.0; 480dpi; 1080x1920; Xiaomi; Redmi Note 4; nikel; mt6797", + "24/7.0; 480dpi; 1080x1920; Xiaomi/xiaomi; Redmi Note 4; mido; qcom", + "23/6.0; 480dpi; 1080x1920; Xiaomi; Redmi Note 4X; nikel; mt6797", + "27/8.1.0; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi Note 5; whyred; qcom", + "23/6.0.1; 480dpi; 1080x1920; Xiaomi; Redmi 4; markw; qcom", + "27/8.1.0; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom", + "25/7.1.2; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom", + "26/8.0.0; 480dpi; 1080x1920; Xiaomi; MI 5; gemini; qcom", + "27/8.1.0; 480dpi; 1080x1920; Xiaomi/xiaomi; Mi A1; tissot_sprout; qcom", + "26/8.0.0; 480dpi; 1080x1920; Xiaomi; MI 6; sagit; qcom", + "25/7.1.1; 440dpi; 1080x1920; Xiaomi; MI MAX 2; oxygen; qcom", + "24/7.0; 480dpi; 1080x1920; Xiaomi; MI 5s; capricorn; qcom", + "26/8.0.0; 480dpi; 1080x1920; samsung; SM-A520F; a5y17lte; samsungexynos7880", + "26/8.0.0; 480dpi; 1080x2076; samsung; SM-G950F; dreamlte; samsungexynos8895", + "26/8.0.0; 640dpi; 1440x2768; samsung; SM-G950F; dreamlte; samsungexynos8895", + "26/8.0.0; 420dpi; 1080x2094; samsung; SM-G955F; dream2lte; samsungexynos8895", + "26/8.0.0; 560dpi; 1440x2792; samsung; SM-G955F; dream2lte; samsungexynos8895", + "24/7.0; 480dpi; 1080x1920; samsung; SM-A510F; a5xelte; samsungexynos7580", + "26/8.0.0; 480dpi; 1080x1920; samsung; SM-G930F; herolte; samsungexynos8890", + "26/8.0.0; 480dpi; 1080x1920; samsung; SM-G935F; hero2lte; samsungexynos8890", + "26/8.0.0; 420dpi; 1080x2094; samsung; SM-G965F; star2lte; samsungexynos9810", + "26/8.0.0; 480dpi; 1080x2076; samsung; SM-A530F; jackpotlte; samsungexynos7885", + "24/7.0; 640dpi; 1440x2560; samsung; SM-G925F; zerolte; samsungexynos7420", + "26/8.0.0; 420dpi; 1080x1920; samsung; SM-A720F; a7y17lte; samsungexynos7880", + "24/7.0; 640dpi; 1440x2560; samsung; SM-G920F; zeroflte; samsungexynos7420", + "24/7.0; 420dpi; 1080x1920; samsung; SM-J730FM; j7y17lte; samsungexynos7870", + "26/8.0.0; 480dpi; 1080x2076; samsung; SM-G960F; starlte; samsungexynos9810", + "26/8.0.0; 420dpi; 1080x2094; samsung; SM-N950F; greatlte; samsungexynos8895", + "26/8.0.0; 420dpi; 1080x2094; samsung; SM-A730F; jackpot2lte; samsungexynos7885", + "26/8.0.0; 420dpi; 1080x2094; samsung; SM-A605FN; a6plte; qcom", + "26/8.0.0; 480dpi; 1080x1920; HUAWEI/HONOR; STF-L09; HWSTF; hi3660", + "27/8.1.0; 480dpi; 1080x2280; HUAWEI/HONOR; COL-L29; HWCOL; kirin970", + "26/8.0.0; 480dpi; 1080x2032; HUAWEI/HONOR; LLD-L31; HWLLD-H; hi6250", + "26/8.0.0; 480dpi; 1080x2150; HUAWEI; ANE-LX1; HWANE; hi6250", + "26/8.0.0; 480dpi; 1080x2032; HUAWEI; FIG-LX1; HWFIG-H; hi6250", + "27/8.1.0; 480dpi; 1080x2150; HUAWEI/HONOR; COL-L29; HWCOL; kirin970", + "26/8.0.0; 480dpi; 1080x2038; HUAWEI/HONOR; BND-L21; HWBND-H; hi6250", + "23/6.0.1; 420dpi; 1080x1920; LeMobile/LeEco; Le X527; le_s2_ww; qcom" + }; + + @NonNull + public static String generateBrowserUA(final int code) { + return browsers[code - 1]; + } + + @NonNull + public static String generateAppUA(final int code, final String lang) { + return "Instagram " + igVersion + " Android (" + devices[code] + "; " + lang + "; " + igVersionCode + ")"; + } +} diff --git a/app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java index 37d123b5..3b5f709f 100644 --- a/app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java +++ b/app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java @@ -25,7 +25,7 @@ public class AddCookiesInterceptor implements Interceptor { } final String userAgentHeader = "User-Agent"; if (request.header(userAgentHeader) == null) { - builder.addHeader(userAgentHeader, hasCookie ? Constants.I_USER_AGENT : Constants.USER_AGENT); + builder.addHeader(userAgentHeader, Utils.settingsHelper.getString(hasCookie ? Constants.APP_UA : Constants.BROWSER_UA)); } final String languageHeader = "Accept-Language"; if (request.header(languageHeader) == null) { diff --git a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java index abaf52a7..ec69ff54 100644 --- a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java +++ b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java @@ -14,14 +14,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.UUID; import awais.instagrabber.models.FollowModel; import awais.instagrabber.repositories.FriendshipRepository; import awais.instagrabber.repositories.responses.FriendshipChangeResponse; import awais.instagrabber.repositories.responses.FriendshipListFetchResponse; import awais.instagrabber.repositories.responses.FriendshipRestrictResponse; -import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import retrofit2.Call; @@ -100,7 +98,7 @@ public class FriendshipService extends BaseService { form.put("_uuid", deviceUuid); form.put("target_user_id", String.valueOf(targetUserId)); final String action = restrict ? "restrict" : "unrestrict"; - final Call request = repository.toggleRestrict(Constants.I_USER_AGENT, action, form); + final Call request = repository.toggleRestrict(action, form); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @@ -140,7 +138,7 @@ public class FriendshipService extends BaseService { form.put("radio_type", "wifi-none"); form.put("user_id", targetUserId); final Map signedForm = Utils.sign(form); - final Call request = repository.change(Constants.I_USER_AGENT, action, targetUserId, signedForm); + final Call request = repository.change(action, targetUserId, signedForm); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @@ -166,8 +164,8 @@ public class FriendshipService extends BaseService { final ServiceCallback callback) { final Map queryMap = new HashMap<>(); if (maxId != null) queryMap.put("max_id", maxId); - final Call request = repository.getList(Constants.I_USER_AGENT, - targetUserId, + final Call request = repository.getList( + targetUserId, follower ? "followers" : "following", queryMap); request.enqueue(new Callback() { diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index 407cfd4a..d8c83313 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -21,6 +21,7 @@ import awais.instagrabber.models.NotificationModel; import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.repositories.NewsRepository; import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -32,6 +33,7 @@ public class NewsService extends BaseService { private final NewsRepository repository; private static NewsService instance; + private static String browserUa, appUa; private NewsService() { final Retrofit retrofit = getRetrofitBuilder() @@ -44,13 +46,15 @@ public class NewsService extends BaseService { if (instance == null) { instance = new NewsService(); } + appUa = Utils.settingsHelper.getString(Constants.APP_UA); + browserUa = Utils.settingsHelper.getString(Constants.BROWSER_UA); return instance; } public void fetchAppInbox(final boolean markAsSeen, final ServiceCallback> callback) { final List result = new ArrayList<>(); - final Call request = repository.appInbox(markAsSeen); + final Call request = repository.appInbox(appUa, markAsSeen); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -90,7 +94,7 @@ public class NewsService extends BaseService { public void fetchWebInbox(final boolean markAsSeen, final ServiceCallback> callback) { - final Call request = repository.webInbox(); + final Call request = repository.webInbox(browserUa); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -206,7 +210,7 @@ public class NewsService extends BaseService { form.put("device_id", UUID.randomUUID().toString()); form.put("module", "discover_people"); form.put("paginate", "false"); - final Call request = repository.getAyml(form); + final Call request = repository.getAyml(appUa, form); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index 7ed4e75b..1c02a92f 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -326,7 +326,7 @@ public class StoriesService extends BaseService { public void getUserStory(final StoryViewerOptions options, final ServiceCallback> callback) { final String url = buildUrl(options); - final Call userStoryCall = repository.getUserStory(Constants.I_USER_AGENT, url); + final Call userStoryCall = repository.getUserStory(url); final boolean isLoc = options.getType() == StoryViewerOptions.Type.LOCATION; final boolean isHashtag = options.getType() == StoryViewerOptions.Type.HASHTAG; final boolean isHighlight = options.getType() == StoryViewerOptions.Type.HIGHLIGHT; @@ -401,7 +401,7 @@ public class StoriesService extends BaseService { form.put(arg1, arg2); final Map signedForm = Utils.sign(form); final Call request = - repository.respondToSticker(Constants.I_USER_AGENT, storyId, stickerId, action, signedForm); + repository.respondToSticker(storyId, stickerId, action, signedForm); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, diff --git a/app/src/main/java/awais/instagrabber/webservices/TagsService.java b/app/src/main/java/awais/instagrabber/webservices/TagsService.java index 004bcd8f..31f2ef78 100644 --- a/app/src/main/java/awais/instagrabber/webservices/TagsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/TagsService.java @@ -46,12 +46,11 @@ public class TagsService extends BaseService { return instance; } - public void follow(@NonNull final String tag, + public void follow(@NonNull final String ua, + @NonNull final String tag, @NonNull final String csrfToken, final ServiceCallback callback) { - final Call request = webRepository.follow(Constants.USER_AGENT, - csrfToken, - tag); + final Call request = webRepository.follow(ua, csrfToken, tag); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -77,12 +76,11 @@ public class TagsService extends BaseService { }); } - public void unfollow(@NonNull final String tag, + public void unfollow(@NonNull final String ua, + @NonNull final String tag, @NonNull final String csrfToken, final ServiceCallback callback) { - final Call request = webRepository.unfollow(Constants.USER_AGENT, - csrfToken, - tag); + final Call request = webRepository.unfollow(ua, csrfToken, tag); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) {