Skip to content
This repository has been archived by the owner. It is now read-only.

Consolidated work on project bond #501

Closed
wants to merge 5 commits into from
Closed
Changes from 1 commit
Commits
File filter
Filter file types
Jump to
Jump to file
Failed to load files.

Always

Just for now

AP-76 AP-77 grpc support and basic signup/login mechanism (#502)

* AP-76 add grpc support

* AB-77 make browser accessible only after login/signup

* requested changes
  • Loading branch information
ravjit-cliqz authored and spacifici committed Nov 14, 2018
commit 3a08cb2528350c134d349f5a28a64a92adc031a6
@@ -62,6 +62,9 @@ buildscript {
classpath 'com.android.tools.build:gradle:3.1.0'
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
/* Cliqz start */
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5"
/* Cliqz end */
}
}

@@ -113,10 +116,12 @@ afterEvaluate {
"-Xlint:-serial",
// Classfile, because javac has a bug with MethodParameters attributes
// with Java 7. https://bugs.openjdk.java.net/browse/JDK-8190452
"-Xlint:-classfile",
"-Xlint:-classfile"]
/* cliqz start o/
// Turn all remaining warnings into errors,
// unless marked by @SuppressWarnings.
"-Werror"]
/o cliqz end*/
}
if (project.name == 'app') {
tasks.withType(JavaCompile) {
@@ -4,6 +4,7 @@ apply plugin: 'com.android.application'
apply plugin: 'checkstyle'
apply plugin: 'com.getkeepsafe.dexcount'
apply plugin: 'findbugs'
apply plugin: 'com.google.protobuf'

apply from: "${topsrcdir}/mobile/android/gradle/product_flavors.gradle"

@@ -331,10 +332,37 @@ dependencies {
/*Cliqz Start*/
//Library for control center donut - chart
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.2'
bondImplementation 'io.grpc:grpc-okhttp:1.15.0'
bondImplementation 'io.grpc:grpc-protobuf-lite:1.15.0'
bondImplementation 'io.grpc:grpc-stub:1.15.0'
bondImplementation 'javax.annotation:javax.annotation-api:1.3.1'
/*Cliqz End*/

}

/* Cliqz start*/
protobuf {
protoc { artifact = 'com.google.protobuf:protoc:3.5.1-1' }
plugins {
javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" }
grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.15.0' // CURRENT_GRPC_VERSION
}
}
generateProtoTasks {
all().each { task ->
task.plugins {
javalite {}
grpc { // Options added to --grpc_out
option 'lite'
}
}

}
ofFlavor('bond')
}
}
/* Cliqz end */

// TODO: (bug 1261486): This impl is not robust -
// we just wanted to land something.
task checkstyle(type: Checkstyle) {
@@ -0,0 +1,145 @@
package org.mozilla.gecko.authentication;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Handler;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewStub;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;

import org.mozilla.gecko.R;
import org.mozilla.gecko.Response;
import org.mozilla.gecko.preferences.PreferenceManager;

import java.util.Timer;
import java.util.TimerTask;

/**
* Copyright © Cliqz 2018
*/
public class LoginHelper implements View.OnClickListener, TalkToServer.ServerCallbacks {

private static final String LOGTAG = LoginHelper.class.getSimpleName();
private static final long POLL_INTERVAL = 10 * 1000; //10 seconds

private Activity mActivity;
private Button mContinueButton;
private EditText mEmailInputField;
private ViewStub mLoginScreenStub;
private String mSecretKey;
private PreferenceManager mPreferenceManager;
private Timer mTimer;
private ProgressBar mProgressBar;

@SuppressLint("HardwareIds")
public LoginHelper(AppCompatActivity activity) {
mActivity = activity;
mSecretKey = Settings.Secure.getString(mActivity.getContentResolver(),
Settings.Secure.ANDROID_ID);
mPreferenceManager = PreferenceManager.getInstance(activity.getBaseContext());
}

public void loginOrRegister() {
final String emailId = mPreferenceManager.getEmailId();
if (emailId.isEmpty()) {
//no email id found show login screen
showLoginScreen();
} else {
//check if device is activated
checkDeviceRegistered(emailId);
}
}

@Override
public void onClick(View view) {
final String emailId = mEmailInputField.getText().toString();
if (emailId.isEmpty()) {
//TODO check for valid email format
} else {
//register device
mPreferenceManager.setEmailId(emailId);
registerDevice(emailId);
}
}

@Override
public void onServerReplied(Response serverResponse, int whichCase) {
switch (whichCase) {
case TalkToServer.IS_DEVICE_ACTIVE:
if (serverResponse.getErrorCount() > 0) {
Log.e(LOGTAG, "Device not activated yet");
Log.e(LOGTAG, serverResponse.getErrorList().toString());
//device is not activated
//show "loginscreen" or probably "waiting for activation screen" ?
showLoginScreen();
} else {
//login successful
//TODO show welcome screen, if first login
}
break;
case TalkToServer.REGISTER_DEVICE:
if (serverResponse.getErrorCount() > 0) {
Log.e(LOGTAG, "Error registering device.");
Log.e(LOGTAG, serverResponse.getErrorList().toString());
} else {
//start polling until user activates device
pollServerForActivation();
}
break;
case TalkToServer.WAIT_FOR_ACTIVATION:
if (serverResponse.getErrorCount() > 0) {
Log.e(LOGTAG, "device is still not active");
} else {
//device activated. hide login screen
mTimer.cancel();
mProgressBar.setVisibility(View.GONE);
mLoginScreenStub.setVisibility(View.GONE);
//TODO show welome screen if first login
}
break;
}
}

private void checkDeviceRegistered(String emailId) {
new TalkToServer(this, TalkToServer.IS_DEVICE_ACTIVE, emailId, mSecretKey).execute();
}

private void registerDevice(String emailId) {
new TalkToServer(this, TalkToServer.REGISTER_DEVICE, emailId, mSecretKey).execute();
}

private void pollServerForActivation() {
final String emailID = mPreferenceManager.getEmailId();
final Handler handler = new Handler();
mTimer = new Timer();
final TimerTask doAsynchronousTask = new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
public void run() {
new TalkToServer(LoginHelper.this,
TalkToServer.WAIT_FOR_ACTIVATION, emailID, mSecretKey).execute();
}
});
}
};
//we should define a limit for how long we keep polling
mTimer.schedule(doAsynchronousTask, 0, POLL_INTERVAL); //execute in every 10secs
mProgressBar.setVisibility(View.VISIBLE);
}

private void showLoginScreen() {
mLoginScreenStub = mActivity.findViewById(R.id.bond_login_screen_stub);
final LinearLayout loginScreenView = (LinearLayout) mLoginScreenStub.inflate();
mContinueButton = loginScreenView.findViewById(R.id.bond_continue_button);
mContinueButton.setOnClickListener(this);
mEmailInputField = loginScreenView.findViewById(R.id.bond_email_input_field);
mProgressBar = loginScreenView.findViewById(R.id.progress_bar);
}
}
@@ -0,0 +1,80 @@
package org.mozilla.gecko.authentication;

import android.os.AsyncTask;

import org.mozilla.gecko.BondV1Grpc;
import org.mozilla.gecko.Error;
import org.mozilla.gecko.ErrorCode;
import org.mozilla.gecko.Response;
import org.mozilla.gecko.UserAuth;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.concurrent.TimeUnit;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

/**
* Copyright © Cliqz 2018
*/
public class TalkToServer extends AsyncTask<Void, Void, Response> {

public interface ServerCallbacks {
void onServerReplied(Response serverResponse, int whichCase);
}

private static final String LOGTAG = TalkToServer.class.getSimpleName();
private static final String HOST = "ambassador.dev.k8s.eu-central-1.clyqz.com";
private static final int PORT = 443;
//different endpoints that can be called on the server
static final int REGISTER_DEVICE = 1;
static final int IS_DEVICE_ACTIVE = 2;
static final int WAIT_FOR_ACTIVATION = 3;
private ManagedChannel mChannel;
private ServerCallbacks mServerCallbacks;
private UserAuth mUserAuth;
private int mWhichCase;

TalkToServer(ServerCallbacks serverCallbacks, int whichCase, String emailId, String secretKey) {
mServerCallbacks = serverCallbacks;
mWhichCase = whichCase;
mUserAuth = UserAuth.newBuilder().setUsername(emailId)
.setPassword(secretKey).build();
}

@Override
protected Response doInBackground(Void... voids) {
try {
mChannel = ManagedChannelBuilder.forAddress(HOST, PORT)
.build();
BondV1Grpc.BondV1BlockingStub stub = BondV1Grpc.newBlockingStub(mChannel);
switch (mWhichCase) {
case REGISTER_DEVICE:
return stub.registerDevice(mUserAuth);
case IS_DEVICE_ACTIVE:
case WAIT_FOR_ACTIVATION:
return stub.isDeviceActivated(mUserAuth);
}
return stub.registerDevice(mUserAuth);
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
return Response.newBuilder().addError(Error.newBuilder().setCode(ErrorCode.UNDEFINED)).build();
}
}

@Override
protected void onPostExecute(Response result) {
try {
if (mChannel != null) {
mChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
mServerCallbacks.onServerReplied(result, mWhichCase);
}
}
@@ -0,0 +1,55 @@
// Service definition for bond server
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.mozilla.gecko";
option java_outer_classname = "BondServerProto";

service BondV1 {
rpc RegisterDevice(UserAuth) returns (Response);
rpc ResendActivationEmail(UserAuth) returns (Response);
rpc IsDeviceActivated(UserAuth) returns (Response);
rpc GetSubscriptions(UserAuth) returns (Subscriptions);
rpc GetVpnCredentials(UserAuth) returns (VpnResponse);
}

// General enume to hold error codes, common to the whole service
enum ErrorCode {
UNDEFINED = 0;
USERNAME_FORMAT_INVALID = 1;
USERNAME_TAKEN = 2;
PASSWORD_INSECURE = 3;
CREDENTIALS_INVALID = 4;
CREDENTIALS_FAILED = 5;
CREDENTIALS_EXPIRED = 6;
INTERNAL = 7;
UNAUTHORIZED = 8;
EMAIL_UNCONFIRMED = 9;
}

message Error {
ErrorCode code = 1;
string msg = 2;
// user facing message if any, localised in <lang>:<value>
map <string, string> usermsg = 3;
}

message Response {
repeated Error error = 1;
string msg = 2;
};

message UserAuth {
string username = 1;
string password = 2;
}

message VpnResponse {
repeated Error error = 1;
string username = 2;
string password = 3;
}

message Subscriptions {
repeated Error error = 1;
repeated string name = 2;
}
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright © Cliqz 2018 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@android:color/black">

<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="200dp"
android:layout_height="200dp"
android:visibility="gone"/>

<EditText
android:id="@+id/bond_email_input_field"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@android:color/white"/>

<Button
android:id="@+id/bond_continue_button"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:text="Continue"/>
</LinearLayout>
@@ -204,6 +204,12 @@

<include layout="@layout/ghostery_splash_screen" />

<ViewStub
android:id="@+id/bond_login_screen_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/bond_login_screen"/>

</FrameLayout>
<!-- Cliqz End -->
<FrameLayout android:id="@+id/tab_history_panel"
ProTip! Use n and p to navigate between commits in a pull request.