Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
AloqaIM-Android
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
AloqaIM-Android
Commits
13837af2
Commit
13837af2
authored
Apr 18, 2017
by
Tiago Cunha
Committed by
GitHub
Apr 18, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #258 from RocketChat/feature/2fa
2FA
parents
825b0b9f
30254dde
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
297 additions
and
6 deletions
+297
-6
MethodCallHelper.java
...c/main/java/chat/rocket/android/api/MethodCallHelper.java
+33
-0
TwoStepAuthException.java
...in/java/chat/rocket/android/api/TwoStepAuthException.java
+16
-0
AbstractServerConfigFragment.java
.../fragment/server_config/AbstractServerConfigFragment.java
+3
-2
LoginContract.java
.../rocket/android/fragment/server_config/LoginContract.java
+2
-0
LoginFragment.java
.../rocket/android/fragment/server_config/LoginFragment.java
+12
-3
LoginPresenter.java
...rocket/android/fragment/server_config/LoginPresenter.java
+9
-1
TwoStepAuthContract.java
...t/android/fragment/server_config/TwoStepAuthContract.java
+20
-0
TwoStepAuthFragment.java
...t/android/fragment/server_config/TwoStepAuthFragment.java
+99
-0
TwoStepAuthPresenter.java
.../android/fragment/server_config/TwoStepAuthPresenter.java
+34
-0
fragment_two_step_auth.xml
app/src/main/res/layout/fragment_two_step_auth.xml
+66
-0
strings.xml
app/src/main/res/values/strings.xml
+3
-0
No files found.
app/src/main/java/chat/rocket/android/api/MethodCallHelper.java
View file @
13837af2
...
...
@@ -84,7 +84,13 @@ public class MethodCallHelper {
if
(
TextUtils
.
isEmpty
(
errMessageJson
))
{
return
Task
.
forError
(
exception
);
}
String
errType
=
new
JSONObject
(
errMessageJson
).
optString
(
"error"
);
String
errMessage
=
new
JSONObject
(
errMessageJson
).
getString
(
"message"
);
if
(
TwoStepAuthException
.
TYPE
.
equals
(
errType
))
{
return
Task
.
forError
(
new
TwoStepAuthException
(
errMessage
));
}
return
Task
.
forError
(
new
Exception
(
errMessage
));
}
else
if
(
exception
instanceof
DDPClientCallback
.
RPC
.
Error
)
{
String
errMessage
=
((
DDPClientCallback
.
RPC
.
Error
)
exception
).
error
.
getString
(
"message"
);
...
...
@@ -214,6 +220,33 @@ public class MethodCallHelper {
});
}
public
Task
<
Void
>
twoStepCodeLogin
(
final
String
usernameOrEmail
,
final
String
password
,
final
String
twoStepCode
)
{
return
call
(
"login"
,
TIMEOUT_MS
,
()
->
{
JSONObject
loginParam
=
new
JSONObject
();
if
(
Patterns
.
EMAIL_ADDRESS
.
matcher
(
usernameOrEmail
).
matches
())
{
loginParam
.
put
(
"user"
,
new
JSONObject
().
put
(
"email"
,
usernameOrEmail
));
}
else
{
loginParam
.
put
(
"user"
,
new
JSONObject
().
put
(
"username"
,
usernameOrEmail
));
}
loginParam
.
put
(
"password"
,
new
JSONObject
()
.
put
(
"digest"
,
CheckSum
.
sha256
(
password
))
.
put
(
"algorithm"
,
"sha-256"
));
JSONObject
twoStepParam
=
new
JSONObject
();
twoStepParam
.
put
(
"login"
,
loginParam
);
twoStepParam
.
put
(
"code"
,
twoStepCode
);
JSONObject
param
=
new
JSONObject
();
param
.
put
(
"totp"
,
twoStepParam
);
return
new
JSONArray
().
put
(
param
);
}).
onSuccessTask
(
CONVERT_TO_JSON_OBJECT
)
.
onSuccessTask
(
task
->
Task
.
forResult
(
task
.
getResult
().
getString
(
"token"
)))
.
onSuccessTask
(
this
::
saveToken
);
}
/**
* Logout.
*/
...
...
app/src/main/java/chat/rocket/android/api/TwoStepAuthException.java
0 → 100644
View file @
13837af2
package
chat
.
rocket
.
android
.
api
;
public
class
TwoStepAuthException
extends
Exception
{
public
static
final
String
TYPE
=
"totp-required"
;
private
static
final
long
serialVersionUID
=
7063596902054234189L
;
public
TwoStepAuthException
()
{
super
();
}
public
TwoStepAuthException
(
String
message
)
{
super
(
message
);
}
}
app/src/main/java/chat/rocket/android/fragment/server_config/AbstractServerConfigFragment.java
View file @
13837af2
...
...
@@ -5,11 +5,12 @@ import android.support.annotation.Nullable;
import
android.support.v4.app.Fragment
;
import
chat.rocket.android.R
;
import
chat.rocket.android.activity.LoginActivity
;
import
chat.rocket.android.fragment.AbstractFragment
;
import
chat.rocket.android.helper.TextUtils
;
abstract
class
AbstractServerConfigFragment
extends
AbstractFragment
{
public
static
final
String
KEY_HOSTNAME
=
"hostname"
;
protected
String
hostname
;
@Override
...
...
@@ -22,7 +23,7 @@ abstract class AbstractServerConfigFragment extends AbstractFragment {
return
;
}
hostname
=
args
.
getString
(
LoginActivity
.
KEY_HOSTNAME
);
hostname
=
args
.
getString
(
KEY_HOSTNAME
);
if
(
TextUtils
.
isEmpty
(
hostname
))
{
finish
();
}
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/LoginContract.java
View file @
13837af2
...
...
@@ -15,6 +15,8 @@ public interface LoginContract {
void
showError
(
String
message
);
void
showLoginServices
(
List
<
LoginServiceConfiguration
>
loginServiceList
);
void
showTwoStepAuth
();
}
interface
Presenter
extends
BaseContract
.
Presenter
<
View
>
{
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/LoginFragment.java
View file @
13837af2
...
...
@@ -26,6 +26,8 @@ public class LoginFragment extends AbstractServerConfigFragment implements Login
private
View
btnEmail
;
private
View
waitingView
;
private
TextView
txtUsername
;
private
TextView
txtPasswd
;
@Override
protected
int
getLayout
()
{
...
...
@@ -46,8 +48,8 @@ public class LoginFragment extends AbstractServerConfigFragment implements Login
@Override
protected
void
onSetupView
()
{
btnEmail
=
rootView
.
findViewById
(
R
.
id
.
btn_login_with_email
);
final
TextView
txtUsername
=
(
TextView
)
rootView
.
findViewById
(
R
.
id
.
editor_username
);
final
TextView
txtPasswd
=
(
TextView
)
rootView
.
findViewById
(
R
.
id
.
editor_passwd
);
txtUsername
=
(
TextView
)
rootView
.
findViewById
(
R
.
id
.
editor_username
);
txtPasswd
=
(
TextView
)
rootView
.
findViewById
(
R
.
id
.
editor_passwd
);
waitingView
=
rootView
.
findViewById
(
R
.
id
.
waiting
);
btnEmail
.
setOnClickListener
(
view
->
presenter
.
login
(
txtUsername
.
getText
().
toString
(),
txtPasswd
.
getText
().
toString
()));
...
...
@@ -55,7 +57,7 @@ public class LoginFragment extends AbstractServerConfigFragment implements Login
final
View
btnUserRegistration
=
rootView
.
findViewById
(
R
.
id
.
btn_user_registration
);
btnUserRegistration
.
setOnClickListener
(
view
->
UserRegistrationDialogFragment
.
create
(
hostname
,
txtUsername
.
getText
().
toString
(),
txtPasswd
.
getText
().
toString
())
.
show
(
getFragmentManager
(),
UserRegistrationDialogFragment
.
class
.
getSimpleName
()
));
.
show
(
getFragmentManager
(),
"UserRegistrationDialogFragment"
));
}
@Override
...
...
@@ -115,6 +117,13 @@ public class LoginFragment extends AbstractServerConfigFragment implements Login
}
}
@Override
public
void
showTwoStepAuth
()
{
showFragmentWithBackStack
(
TwoStepAuthFragment
.
create
(
hostname
,
txtUsername
.
getText
().
toString
(),
txtPasswd
.
getText
().
toString
()
));
}
@Override
public
void
onResume
()
{
super
.
onResume
();
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/LoginPresenter.java
View file @
13837af2
...
...
@@ -8,6 +8,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import
bolts.Task
;
import
chat.rocket.android.BackgroundLooper
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.api.TwoStepAuthException
;
import
chat.rocket.android.helper.Logger
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.shared.BasePresenter
;
...
...
@@ -74,7 +75,14 @@ public class LoginPresenter extends BasePresenter<LoginContract.View>
.
continueWith
(
task
->
{
if
(
task
.
isFaulted
())
{
view
.
hideLoader
();
view
.
showError
(
task
.
getError
().
getMessage
());
final
Exception
error
=
task
.
getError
();
if
(
error
instanceof
TwoStepAuthException
)
{
view
.
showTwoStepAuth
();
}
else
{
view
.
showError
(
error
.
getMessage
());
}
}
return
null
;
});
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/TwoStepAuthContract.java
0 → 100644
View file @
13837af2
package
chat
.
rocket
.
android
.
fragment
.
server_config
;
import
chat.rocket.android.shared.BaseContract
;
public
interface
TwoStepAuthContract
{
interface
View
extends
BaseContract
.
View
{
void
showLoading
();
void
hideLoading
();
void
showError
(
String
message
);
}
interface
Presenter
extends
BaseContract
.
Presenter
<
View
>
{
void
onCode
(
String
twoStepAuthCode
);
}
}
app/src/main/java/chat/rocket/android/fragment/server_config/TwoStepAuthFragment.java
0 → 100644
View file @
13837af2
package
chat
.
rocket
.
android
.
fragment
.
server_config
;
import
android.os.Bundle
;
import
android.support.annotation.Nullable
;
import
android.support.design.widget.Snackbar
;
import
android.view.View
;
import
android.widget.TextView
;
import
chat.rocket.android.R
;
import
chat.rocket.android.api.MethodCallHelper
;
public
class
TwoStepAuthFragment
extends
AbstractServerConfigFragment
implements
TwoStepAuthContract
.
View
{
private
static
final
String
ARG_USERNAME_OR_EMAIL
=
"usernameOrEmail"
;
private
static
final
String
ARG_PASSWORD
=
"password"
;
private
View
waitingView
;
private
View
submitButton
;
private
TwoStepAuthContract
.
Presenter
presenter
;
public
static
TwoStepAuthFragment
create
(
String
hostname
,
String
usernameOrEmail
,
String
password
)
{
Bundle
args
=
new
Bundle
();
args
.
putString
(
AbstractServerConfigFragment
.
KEY_HOSTNAME
,
hostname
);
args
.
putString
(
ARG_USERNAME_OR_EMAIL
,
usernameOrEmail
);
args
.
putString
(
ARG_PASSWORD
,
password
);
TwoStepAuthFragment
fragment
=
new
TwoStepAuthFragment
();
fragment
.
setArguments
(
args
);
return
fragment
;
}
@Override
public
void
onCreate
(
@Nullable
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
Bundle
args
=
getArguments
();
if
(
args
==
null
||
!
args
.
containsKey
(
ARG_USERNAME_OR_EMAIL
)
||
!
args
.
containsKey
(
ARG_PASSWORD
))
{
finish
();
return
;
}
presenter
=
new
TwoStepAuthPresenter
(
new
MethodCallHelper
(
getContext
(),
hostname
),
args
.
getString
(
ARG_USERNAME_OR_EMAIL
),
args
.
getString
(
ARG_PASSWORD
)
);
}
@Override
public
void
onResume
()
{
super
.
onResume
();
presenter
.
bindView
(
this
);
}
@Override
public
void
onPause
()
{
presenter
.
release
();
super
.
onPause
();
}
@Override
public
void
showLoading
()
{
submitButton
.
setEnabled
(
false
);
waitingView
.
setVisibility
(
View
.
VISIBLE
);
}
@Override
public
void
hideLoading
()
{
waitingView
.
setVisibility
(
View
.
GONE
);
submitButton
.
setEnabled
(
true
);
}
@Override
public
void
showError
(
String
message
)
{
Snackbar
.
make
(
rootView
,
message
,
Snackbar
.
LENGTH_LONG
).
show
();
}
@Override
protected
int
getLayout
()
{
return
R
.
layout
.
fragment_two_step_auth
;
}
@Override
protected
void
onSetupView
()
{
waitingView
=
rootView
.
findViewById
(
R
.
id
.
waiting
);
final
TextView
twoStepCodeTextView
=
(
TextView
)
rootView
.
findViewById
(
R
.
id
.
two_step_code
);
submitButton
=
rootView
.
findViewById
(
R
.
id
.
btn_two_step_login
);
submitButton
.
setOnClickListener
(
view
->
{
presenter
.
onCode
(
twoStepCodeTextView
.
getText
().
toString
());
});
}
}
app/src/main/java/chat/rocket/android/fragment/server_config/TwoStepAuthPresenter.java
0 → 100644
View file @
13837af2
package
chat
.
rocket
.
android
.
fragment
.
server_config
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.shared.BasePresenter
;
public
class
TwoStepAuthPresenter
extends
BasePresenter
<
TwoStepAuthContract
.
View
>
implements
TwoStepAuthContract
.
Presenter
{
private
final
MethodCallHelper
methodCallHelper
;
private
final
String
usernameOrEmail
;
private
final
String
password
;
public
TwoStepAuthPresenter
(
MethodCallHelper
methodCallHelper
,
String
usernameOrEmail
,
String
password
)
{
this
.
methodCallHelper
=
methodCallHelper
;
this
.
usernameOrEmail
=
usernameOrEmail
;
this
.
password
=
password
;
}
@Override
public
void
onCode
(
String
twoStepAuthCode
)
{
view
.
showLoading
();
methodCallHelper
.
twoStepCodeLogin
(
usernameOrEmail
,
password
,
twoStepAuthCode
)
.
continueWith
(
task
->
{
if
(
task
.
isFaulted
())
{
view
.
hideLoading
();
view
.
showError
(
task
.
getError
().
getMessage
());
}
return
null
;
});
}
}
app/src/main/res/layout/fragment_two_step_auth.xml
0 → 100644
View file @
13837af2
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"?attr/colorPrimaryDark"
>
<LinearLayout
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:background=
"@color/white"
android:minWidth=
"288dp"
android:orientation=
"vertical"
android:padding=
"@dimen/margin_24"
>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_horizontal"
style=
"@style/Base.TextAppearance.AppCompat.Large"
android:text=
"@string/two_factor_authentication_title"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
style=
"@style/Base.TextAppearance.AppCompat.Body1"
android:text=
"@string/open_your_authentication_app_and_enter_the_code"
/>
<android.support.design.widget.TextInputLayout
android:id=
"@+id/text_input_two_step_code"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
>
<android.support.design.widget.TextInputEditText
android:id=
"@+id/two_step_code"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:hint=
"@string/two_factor_code"
android:imeOptions=
"actionNext"
android:inputType=
"textWebEmailAddress"
android:maxLines=
"1"
/>
</android.support.design.widget.TextInputLayout>
<Space
android:layout_width=
"wrap_content"
android:layout_height=
"@dimen/margin_16"
/>
<android.support.design.widget.FloatingActionButton
android:id=
"@+id/btn_two_step_login"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"end|bottom"
app:elevation=
"2dp"
app:fabSize=
"normal"
app:srcCompat=
"@drawable/ic_arrow_forward_white_24dp"
/>
<chat.rocket.android.widget.WaitingView
android:id=
"@+id/waiting"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:visibility=
"gone"
/>
</LinearLayout>
</FrameLayout>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
13837af2
...
...
@@ -47,4 +47,7 @@
<string
name=
"connection_error_try_later"
>
There\'s a connection error. Please try later.
</string>
<string
name=
"version_info_text"
>
Version: %s
</string>
<string
name=
"two_factor_authentication_title"
>
Two-factor authentication
</string>
<string
name=
"open_your_authentication_app_and_enter_the_code"
>
Open your authentication app and enter the code
</string>
<string
name=
"two_factor_code"
>
Two-factor code
</string>
</resources>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment