diff --git a/.github/workflows/browerstack.yml b/.github/workflows/browerstack.yml
index 2da8b7f40..f28cccd32 100644
--- a/.github/workflows/browerstack.yml
+++ b/.github/workflows/browerstack.yml
@@ -30,7 +30,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v4
with:
- go-version: 1.19
+ go-version-file: "go.mod"
- name: Granting private modules access
run: |
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 74355fd60..5ec8ff34c 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -20,11 +20,13 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
- go-version: 1.19
+ go-version-file: "go.mod"
- name: Granting private modules access
run: |
git config --global url."https://${{ secrets.CI_PRIVATE_REPOS_GH_TOKEN }}:x-oauth-basic@github.com/".insteadOf "https://github.com/"
- name: Run Unit tests
+ env:
+ GOPRIVATE: github.com/getlantern
run: |
go mod tidy
go test -failfast -coverprofile=profile.cov ./...
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6cb7682ee..51c04c035 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,7 +1,10 @@
name: Publish releases
on:
- workflow_dispatch:
+ push:
+ branches: [ android-migrate ]
+ tags:
+ - '*'
permissions:
contents: read
@@ -60,7 +63,7 @@ jobs:
runs-on:
group: large-runners
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
lfs: true
@@ -70,14 +73,17 @@ jobs:
# Install Flutter
- uses: subosito/flutter-action@v2
with:
- flutter-version: "3.10.5"
+ flutter-version: "3.16.9"
channel: "stable"
- run: flutter --version
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v4
with:
- go-version: 1.19
+ go-version-file: "go.mod"
+
+ - name: Install latest protoc-gen-go
+ run: go install github.com/golang/protobuf/protoc-gen-go@latest
- name: Granting private modules access
run: |
@@ -125,10 +131,13 @@ jobs:
fileDir: './android/app'
encodedString: ${{ secrets.KEYSTORE }}
+ - run: touch app.env
+
- name: Build Android installers
run: make package-android
env:
INTERSTITIAL_AD_UNIT: "${{ secrets.INTERSTITIAL_AD_UNIT_ID }}"
+ SENTRY_AUTH_TOKEN: "${{ secrets.SENTRY_AUTH_TOKEN }}"
VERSION: "${{ env.version }}"
- uses: actions/upload-artifact@v3
diff --git a/.gitignore b/.gitignore
index e47fba771..be3476446 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,3 +77,4 @@ appium_kotlin/app/src/test/resources/local/local_config.json
ios/internalsdk/Internalsdk.xcframework/
android/app/libs/liblantern-all.aar
+*.env
diff --git a/Makefile b/Makefile
index 0a039de59..939f1f458 100644
--- a/Makefile
+++ b/Makefile
@@ -18,15 +18,15 @@ lib/messaging/protos_flutteronly/messaging.pb.dart: protos_flutteronly/messaging
lib/vpn/protos_shared/vpn.pb.dart: protos_shared/vpn.proto
@protoc --dart_out=./lib/vpn --plugin=protoc-gen-dart=$$HOME/.pub-cache/bin/protoc-gen-dart protos_shared/vpn.proto
-internalsdk/protos/%.pb.go: protos_shared/%.proto
- @echo "Generating Go protobuf for $<"
- @protoc --plugin=protoc-gen-go=build/protoc-gen-go \
- --go_out=internalsdk \
- $<
+#internalsdk/protos/%.pb.go: protos_shared/%.proto
+# @echo "Generating Go protobuf for $<"
+# @protoc --plugin=protoc-gen-go=build/protoc-gen-go \
+# --go_out=internalsdk \
+# $<
-#internalsdk/protos/vpn.pb.go: protos_shared/vpn.proto
-# @protoc --go_out=internalsdk protos_shared/vpn.proto
+internalsdk/protos/vpn.pb.go: protos_shared/vpn.proto
+ @protoc --go_out=internalsdk protos_shared/vpn.proto
# Compiles autorouter routes
routes: lib/core/router/router.gr.dart
@@ -42,8 +42,6 @@ TEST ?= *_test
# integration-test:
# @flutter drive --driver test_driver/integration_driver.dart --debug --flavor prod --target `ls integration_test/$(TEST).dart`
-GO_VERSION := 1.19
-
TAG ?= $$VERSION
TAG_HEAD := $(shell git rev-parse HEAD)
INSTALLER_NAME ?= lantern-installer
@@ -205,12 +203,6 @@ tag: require-version
git commit -m "Updated changelog for $$VERSION" && \
git push
-define check-go-version
- if [ -z '${IGNORE_GO_VERSION}' ] && go version | grep -q -v $(GO_VERSION); then \
- echo "go $(GO_VERSION) is required." && exit 1; \
- fi
-endef
-
guard-%:
@ if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi
@@ -220,6 +212,9 @@ require-app: guard-APP
.PHONY: require-version
require-version: guard-VERSION
+.PHONY: require-sentry-auth-token
+require-secrets-dir: guard-SENTRY_AUTH_TOKEN
+
.PHONY: require-secrets-dir
require-secrets-dir: guard-SECRETS_DIR
@@ -271,8 +266,7 @@ release-autoupdate: require-version
release: require-version require-s3cmd require-wget require-lantern-binaries require-release-track release-prod copy-beta-installers-to-mirrors invalidate-getlantern-dot-org upload-aab-to-play
-$(ANDROID_LIB):
- $(call check-go-version) && \
+$(ANDROID_LIB): $(GO_SOURCES)
go env -w 'GOPRIVATE=github.com/getlantern/*' && \
go install golang.org/x/mobile/cmd/gomobile && \
gomobile init && \
@@ -327,11 +321,10 @@ pubget:
@flutter pub get
$(MOBILE_DEBUG_APK): $(MOBILE_SOURCES) $(GO_SOURCES)
- @$(call check-go-version) && \
make do-android-debug && \
cp $(MOBILE_ANDROID_DEBUG) $(MOBILE_DEBUG_APK)
-$(MOBILE_RELEASE_APK): $(MOBILE_SOURCES) $(GO_SOURCES) $(MOBILE_ANDROID_LIB) require-sentry
+$(MOBILE_RELEASE_APK): $(MOBILE_SOURCES) $(GO_SOURCES) $(MOBILE_ANDROID_LIB) require-sentry require-sentry-auth-token
echo $(MOBILE_ANDROID_LIB) && \
mkdir -p ~/.gradle && \
ln -fs $(MOBILE_DIR)/gradle.properties . && \
@@ -358,7 +351,7 @@ $(MOBILE_BUNDLE): $(MOBILE_SOURCES) $(GO_SOURCES) $(MOBILE_ANDROID_LIB) require-
STICKY_CONFIG="$$STICKY_CONFIG" && \
PAYMENT_PROVIDER="$$PAYMENT_PROVIDER" && \
$(GRADLE) -PlanternVersion=$$VERSION -PlanternRevisionDate=$(REVISION_DATE) -PandroidArch=$(ANDROID_ARCH) -PandroidArchJava="$(ANDROID_ARCH_JAVA)" \
- -PddClientToken=$(DD_CLIENT_TOKEN) -PddApplicationID=$(DD_APPLICATION_ID) -PproServerUrl=$(PRO_SERVER_URL) -PpaymentProvider=$(PAYMENT_PROVIDER) \
+ -PproServerUrl=$(PRO_SERVER_URL) -PpaymentProvider=$(PAYMENT_PROVIDER) \
-Pcountry=$(COUNTRY) -PplayVersion=true -PuseStaging=$(STAGING) -PstickyConfig=$(STICKY_CONFIG) -b $(MOBILE_DIR)/app/build.gradle bundlePlay && \
sentry-cli upload-dif --wait -o getlantern -p android build/app/intermediates/merged_native_libs/prodPlay/out/lib && \
cp $(MOBILE_ANDROID_BUNDLE) $(MOBILE_BUNDLE)
@@ -399,7 +392,7 @@ android-release-install: $(MOBILE_RELEASE_APK)
$(ADB) install -r $(MOBILE_RELEASE_APK)
package-android: pubget require-version
- @ANDROID_ARCH=arm32 make android-release && \
+ @ANDROID_ARCH=all make android-release && \
ANDROID_ARCH=all make android-bundle && \
echo "-> $(MOBILE_RELEASE_APK)"
@@ -442,7 +435,7 @@ build-framework: assert-go-version install-gomobile
go env -w 'GOPRIVATE=github.com/getlantern/*' && \
gomobile init && \
gomobile bind -target=ios,iossimulator \
- -tags='headless lantern ios' \
+ -tags='headless lantern ios netgo' \
-ldflags="$(LDFLAGS)" \
$(GOMOBILE_EXTRA_BUILD_FLAGS) \
github.com/getlantern/android-lantern/internalsdk github.com/getlantern/pathdb/testsupport github.com/getlantern/pathdb/minisql github.com/getlantern/flashlight/v7/ios
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 94cad54f4..48407fa79 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -6,7 +6,7 @@ plugins {
id 'kotlin-parcelize'
id 'kotlin-kapt'
id 'com.google.protobuf'
- id "io.sentry.android.gradle" version "3.13.0"
+ id "io.sentry.android.gradle" version "4.2.0"
}
def localProperties = new Properties()
@@ -395,7 +395,7 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
- implementation "androidx.webkit:webkit:1.7.0"
+ implementation "androidx.webkit:webkit:1.9.0"
implementation 'com.kyleduo.switchbutton:library:2.1.0'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1'
@@ -415,7 +415,8 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
// Google Play libraries
- implementation 'com.android.billingclient:billing:6.0.1'
+ implementation 'com.android.billingclient:billing:6.1.0'
+// implementation 'com.android.billingclient:billing-ktx:6.1.0'
implementation 'com.google.android.gms:play-services-base:18.2.0'
implementation 'com.google.android.gms:play-services-ads:22.4.0'
@@ -446,6 +447,7 @@ dependencies {
androidTestImplementation 'com.squareup.okhttp3:okhttp:4.9.2'
testImplementation 'junit:junit:4.13.2'
+ testImplementation "io.mockk:mockk:1.13.5"
implementation "com.github.YarikSOffice:lingver:1.3.0"
// from https://github.com/getlantern/opus_android
@@ -460,6 +462,25 @@ apply plugin: 'com.google.gms.google-services'
sentry {
+ // Disables or enables debug log output, e.g. for for sentry-cli.
+ // Default is disabled.
+ debug = false
+
+ // The slug of the Sentry organization to use for uploading proguard mappings/source contexts.
+ org = "getlantern"
+
+ // The slug of the Sentry project to use for uploading proguard mappings/source contexts.
+ projectName = "android"
+
+ // The authentication token to use for uploading proguard mappings/source contexts.
+ // WARNING: Do not expose this token in your build.gradle files, but rather set an environment
+ // variable and read it into this property.
+ authToken = System.getenv("SENTRY_AUTH_TOKEN")
+
+ // The url of your Sentry instance. If you're using SAAS (not self hosting) you do not have to
+ // set this. If you are self hosting you can set your URL here
+ url = null
+
// Disables or enables the handling of Proguard mapping for Sentry.
// If enabled the plugin will generate a UUID and will take care of
// uploading the mapping to Sentry. If disabled, all the logic
diff --git a/android/app/libs/liblantern-all.aar b/android/app/libs/liblantern-all.aar
index 687cb15d3..97cf10f47 100644
--- a/android/app/libs/liblantern-all.aar
+++ b/android/app/libs/liblantern-all.aar
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dcc19bfe34f4e22d0cfa8b70365fdea09461a30437b02c321aebfd73097b7757
-size 79879184
+oid sha256:ba02d66cad4c82257df848c01eb9f2b3bb9562cb1ef2edb674cce5f438cef4c3
+size 82901087
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index f95e8b487..f8f0010eb 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -10,13 +10,17 @@
+
+
+
-
+
diff --git a/android/app/src/main/java/org/getlantern/lantern/model/LanternHttpClient.java b/android/app/src/main/java/org/getlantern/lantern/model/LanternHttpClient.java
deleted file mode 100644
index c6e8cd789..000000000
--- a/android/app/src/main/java/org/getlantern/lantern/model/LanternHttpClient.java
+++ /dev/null
@@ -1,495 +0,0 @@
-package org.getlantern.lantern.model;
-
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.google.gson.reflect.TypeToken;
-
-import org.getlantern.lantern.LanternApp;
-import org.getlantern.lantern.util.Json;
-import org.getlantern.mobilesdk.Logger;
-import org.getlantern.mobilesdk.util.HttpClient;
-
-import java.io.IOException;
-import java.lang.reflect.Type;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import okhttp3.CacheControl;
-import okhttp3.Call;
-import okhttp3.Callback;
-import okhttp3.FormBody;
-import okhttp3.Headers;
-import okhttp3.HttpUrl;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import okhttp3.ResponseBody;
-import okio.Buffer;
-
-/**
- * An OkHttp-based HTTP client.
- */
-public class LanternHttpClient extends HttpClient {
- private static final String TAG = LanternHttpClient.class.getName();
-
- // the standard user headers sent with most Pro requests
- private static final String DEVICE_ID_HEADER = "X-Lantern-Device-Id";
- private static final String USER_ID_HEADER = "X-Lantern-User-Id";
- private static final String PRO_TOKEN_HEADER = "X-Lantern-Pro-Token";
- private static final String APP_VERSION_HEADER = "X-Lantern-Version";
- private static final String PLATFORM_HEADER = "X-Lantern-Platform";
-
- private static final MediaType JSON
- = MediaType.parse("application/json; charset=utf-8");
-
- /**
- * Creates a new HTTP client
- */
- public LanternHttpClient() {
- super();
- }
-
- /**
- * Creates a new HTTP client
- *
- * @param httpClient The HTTP client to use.
- */
- public LanternHttpClient(final OkHttpClient httpClient) {
- super(httpClient);
- }
-
- public static HttpUrl createProUrl(final String uri) {
- return createProUrl(uri, null);
- }
-
- /**
- * Constructs a url for a request to the pro server
- *
- * @param uri the requested resource
- * @param params any query params to include with the url
- * @return a URL
- */
- public static HttpUrl createProUrl(final String uri, final Map params) {
- final String url = String.format("http://localhost/pro%s", uri);
- HttpUrl.Builder builder = HttpUrl.parse(url).newBuilder();
- if (params != null) {
- for (Map.Entry param : params.entrySet()) {
- builder.addQueryParameter(param.getKey(), param.getValue());
- }
- }
- return builder.build();
- }
-
- /**
- * The HTTP headers expected with Pro requests for a user
- */
- private Map userHeaders() {
- final Map headers = new HashMap();
- headers.put(DEVICE_ID_HEADER, LanternApp.getSession().getDeviceID());
- headers.put(PRO_TOKEN_HEADER, LanternApp.getSession().getToken());
- headers.put(USER_ID_HEADER, String.valueOf(LanternApp.getSession().getUserID()));
- headers.put(PLATFORM_HEADER, "android");
- headers.put(APP_VERSION_HEADER, Utils.appVersion(LanternApp.getAppContext()));
- headers.putAll(LanternApp.getSession().getInternalHeaders());
- Logger.d(TAG, "User headers " + headers);
- return headers;
- }
-
- public void request(@NonNull final String method, @NonNull final HttpUrl url,
- final HttpCallback cb) {
- request(method, url, null, null, cb);
- }
-
- public void request(@NonNull final String method, @NonNull final HttpUrl url,
- final ProCallback cb) {
- proRequest(method, url, null, null, cb);
- }
-
- public void request(@NonNull final String method, @NonNull final HttpUrl url,
- final boolean addProHeaders,
- RequestBody body, final HttpCallback cb) {
- if (addProHeaders) {
- request(method, url, userHeaders(), body, cb);
- } else {
- request(method, url, null, body, cb);
- }
- }
-
- public void request(@NonNull final String method, @NonNull final HttpUrl url,
- RequestBody body, final ProCallback cb) {
- proRequest(method, url, userHeaders(), body, cb);
- }
-
- /**
- * GET request.
- *
- * @param url request URL
- * @param cb for notifying the caller of an HTTP response or failure
- */
- public void get(@NonNull final HttpUrl url, final ProCallback cb) {
- proRequest("GET", url, userHeaders(), null, cb);
- }
-
- /**
- * POST request.
- *
- * @param url request URL
- * @param body the data enclosed with the HTTP message
- * @param cb the callback responded with an HTTP response or failure
- */
- public void post(@NonNull final HttpUrl url,
- final RequestBody body, @NonNull final ProCallback cb) {
- proRequest("POST", url, userHeaders(), body, cb);
- }
-
- private void processPlans(List fetched, final PlansCallback cb, InAppBilling inAppBilling) {
- Map plans = new HashMap();
- Logger.debug(TAG, "Pro plans: " + fetched);
- for (ProPlan plan : fetched) {
- if (plan != null) {
- plan.formatCost();
- Logger.debug(TAG, "New plan is " + plan);
- plans.put(plan.getId(), plan);
- }
- }
- if (inAppBilling != null) {
- // this means we're in the play store, use the configured plans from there but with the
- // renewal bonus from the server side plans
- Map regularPlans = new HashMap<>();
- for (Map.Entry entry : plans.entrySet()) {
- // Plans from the pro server have a version suffix, like '1y-usd-9' but plans from
- // the Play Store don't, like '1y-usd'. So we normalize by dropping the version
- // suffix.
- regularPlans.put(entry.getKey().substring(0, entry.getKey().lastIndexOf("-")), entry.getValue());
- }
- plans = inAppBilling.getPlans();
- for (Map.Entry entry : plans.entrySet()) {
- ProPlan regularPlan = regularPlans.get(entry.getKey());
- if (regularPlan != null) {
- entry.getValue().updateRenewalBonusExpected(regularPlan.getRenewalBonusExpected());
- }
- }
- }
- cb.onSuccess(plans);
- }
-
- private void processPlansV1(final JsonObject result, final PlansCallback cb, InAppBilling inAppBilling) {
- String stripePubKey = result.get("providers").getAsJsonObject().get("stripe").getAsJsonObject().get("pubKey").getAsString();
- LanternApp.getSession().setStripePubKey(stripePubKey);
- Type listType = new TypeToken>() {
- }.getType();
- Logger.debug(TAG, "Plans: " + result.get("plans"));
- final List fetched = Json.gson.fromJson(result.get("plans"), listType);
- processPlans(fetched, cb, inAppBilling);
- }
-
- private void processPlansV3(final JsonObject result, final PlansV3Callback cb, InAppBilling inAppBilling) {
- Type mapType = new TypeToken