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
e797d903
Unverified
Commit
e797d903
authored
Mar 29, 2018
by
Lucio Maciel
Committed by
GitHub
Mar 29, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #965 from RocketChat/new/login-with-gitlab
[NEW] Login with Gitlab (OAuth).
parents
03b36264
7d813c93
Changes
17
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
451 additions
and
187 deletions
+451
-187
gradle-wrapper.properties
app/gradle/wrapper/gradle-wrapper.properties
+1
-1
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+5
-0
LoginPresenter.kt
...droid/authentication/login/presentation/LoginPresenter.kt
+151
-120
LoginView.kt
...et/android/authentication/login/presentation/LoginView.kt
+30
-10
LoginFragment.kt
...t/rocket/android/authentication/login/ui/LoginFragment.kt
+44
-23
SignupPresenter.kt
...oid/authentication/signup/presentation/SignupPresenter.kt
+5
-2
AutoCompleteType.kt
.../chat/rocket/android/chatroom/adapter/AutoCompleteType.kt
+1
-1
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+1
-1
PinnedMessagesPresenter.kt
.../android/chatroom/presentation/PinnedMessagesPresenter.kt
+1
-1
ChatRoomsPresenter.kt
...cket/android/chatrooms/presentation/ChatRoomsPresenter.kt
+43
-10
ChatRoomsFragment.kt
...ava/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
+1
-1
UrlHelper.kt
app/src/main/java/chat/rocket/android/helper/UrlHelper.kt
+21
-0
Text.kt
...src/main/java/chat/rocket/android/util/extensions/Text.kt
+20
-1
CasWebViewActivity.kt
.../chat/rocket/android/webview/cas/ui/CasWebViewActivity.kt
+11
-15
GitlabWebViewActivity.kt
...rocket/android/webview/gitlab/ui/GitlabWebViewActivity.kt
+108
-0
fragment_authentication_log_in.xml
app/src/main/res/layout/fragment_authentication_log_in.xml
+7
-0
gradle-wrapper.properties
gradle/wrapper/gradle-wrapper.properties
+1
-1
No files found.
app/gradle/wrapper/gradle-wrapper.properties
View file @
e797d903
...
...
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath
=
wrapper/dists
zipStoreBase
=
GRADLE_USER_HOME
zipStorePath
=
wrapper/dists
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-4.
1
-all.zip
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-4.
6
-all.zip
app/src/main/AndroidManifest.xml
View file @
e797d903
...
...
@@ -54,6 +54,11 @@
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
android:theme=
"@style/AppTheme"
/>
<activity
android:name=
".webview.gitlab.ui.GitlabWebViewActivity"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
android:theme=
"@style/AppTheme"
/>
<activity
android:name=
".chatroom.ui.ChatRoomActivity"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
...
...
app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
View file @
e797d903
This diff is collapsed.
Click to expand it.
app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginView.kt
View file @
e797d903
...
...
@@ -37,7 +37,7 @@ interface LoginView : LoadingView, MessageView, InternetView {
/**
* Shows the CAS button if the sign in/sign out via CAS protocol is enabled by the server settings.
*
* REMARK: We must set up the CAS button listener [setupCasButtonListener].
* REMARK: We must set up the CAS button listener
before showing it
[setupCasButtonListener].
*/
fun
showCasButton
()
...
...
@@ -49,8 +49,8 @@ interface LoginView : LoadingView, MessageView, InternetView {
/**
* Setups the CAS button when tapped.
*
* @param casUrl The CAS URL to
login/sign up
with.
* @param casToken The requested
Token
sent to the CAS server.
* @param casUrl The CAS URL to
authenticate
with.
* @param casToken The requested
token to be
sent to the CAS server.
*/
fun
setupCasButtonListener
(
casUrl
:
String
,
casToken
:
String
)
...
...
@@ -96,40 +96,60 @@ interface LoginView : LoadingView, MessageView, InternetView {
fun
hideLoginButton
()
/**
* Shows the "login by Facebook view if it is enable
d
by the server settings.
* Shows the "login by Facebook view if it is enable by the server settings.
*/
fun
enableLoginByFacebook
()
/**
* Shows the "login by Github" view if it is enabled by the server settings.
* Shows the "login by Github" view if it is enable by the server settings.
*
* REMARK: We must set up the Github button listener before enabling it [setupGithubButtonListener].
*/
fun
enableLoginByGithub
()
/**
* Shows the "login by Google" view if it is enabled by the server settings.
* Setups the Github button when tapped.
*
* @param githubUrl The Github OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later (to protect against forgery attacks).
*/
fun
setupGithubButtonListener
(
githubUrl
:
String
,
state
:
String
)
/**
* Shows the "login by Google" view if it is enable by the server settings.
*/
fun
enableLoginByGoogle
()
/**
* Shows the "login by Linkedin" view if it is enable
d
by the server settings.
* Shows the "login by Linkedin" view if it is enable by the server settings.
*/
fun
enableLoginByLinkedin
()
/**
* Shows the "login by Meteor" view if it is enable
d
by the server settings.
* Shows the "login by Meteor" view if it is enable by the server settings.
*/
fun
enableLoginByMeteor
()
/**
* Shows the "login by Twitter" view if it is enable
d
by the server settings.
* Shows the "login by Twitter" view if it is enable by the server settings.
*/
fun
enableLoginByTwitter
()
/**
* Shows the "login by Gitlab" view if it is enabled by the server settings.
* Shows the "login by Gitlab" view if it is enable by the server settings.
*
* REMARK: We must set up the Gitlab button listener before enabling it [setupGitlabButtonListener].
*/
fun
enableLoginByGitlab
()
/**
* Setups the Gitlab button when tapped.
*
* @param gitlabUrl The Gitlab OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later (to protect against forgery attacks).
*/
fun
setupGitlabButtonListener
(
gitlabUrl
:
String
,
state
:
String
)
/**
* Setups the FloatingActionButton to show more social accounts views (expanding the oauth view interface to show the remaining view(s)).
*/
...
...
app/src/main/java/chat/rocket/android/authentication/login/ui/LoginFragment.kt
View file @
e797d903
...
...
@@ -19,12 +19,17 @@ import chat.rocket.android.authentication.login.presentation.LoginView
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.TextHelper
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.webview.cas.ui.webViewIntent
import
chat.rocket.android.webview.cas.ui.INTENT_CAS_TOKEN
import
chat.rocket.android.webview.cas.ui.casWebViewIntent
import
chat.rocket.android.webview.gitlab.ui.INTENT_OAUTH_CREDENTIAL_SECRET
import
chat.rocket.android.webview.gitlab.ui.INTENT_OAUTH_CREDENTIAL_TOKEN
import
chat.rocket.android.webview.gitlab.ui.gitlabWebViewIntent
import
dagger.android.support.AndroidSupportInjection
import
kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import
javax.inject.Inject
internal
const
val
REQUEST_CODE_FOR_CAS
=
1
internal
const
val
REQUEST_CODE_FOR_OAUTH
=
2
class
LoginFragment
:
Fragment
(),
LoginView
{
@Inject
lateinit
var
presenter
:
LoginPresenter
...
...
@@ -64,10 +69,14 @@ class LoginFragment : Fragment(), LoginView {
}
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
if
(
re
questCode
==
REQUEST_CODE_FOR_CAS
)
{
if
(
re
sultCode
==
Activity
.
RESULT_OK
)
{
if
(
re
sultCode
==
Activity
.
RESULT_OK
)
{
if
(
re
questCode
==
REQUEST_CODE_FOR_CAS
)
{
data
?.
apply
{
presenter
.
authenticateWithCas
(
getStringExtra
(
"cas_token"
))
presenter
.
authenticateWithCas
(
getStringExtra
(
INTENT_CAS_TOKEN
))
}
}
else
if
(
requestCode
==
REQUEST_CODE_FOR_OAUTH
)
{
data
?.
apply
{
presenter
.
authenticateWithOauth
(
getStringExtra
(
INTENT_OAUTH_CREDENTIAL_TOKEN
),
getStringExtra
(
INTENT_OAUTH_CREDENTIAL_SECRET
))
}
}
}
...
...
@@ -121,7 +130,7 @@ class LoginFragment : Fragment(), LoginView {
override
fun
setupLoginButtonListener
()
{
button_log_in
.
setOnClickListener
{
presenter
.
authenticate
(
text_username_or_email
.
textContent
,
text_password
.
textContent
)
presenter
.
authenticate
WithUserAndPassword
(
text_username_or_email
.
textContent
,
text_password
.
textContent
)
}
}
...
...
@@ -147,7 +156,7 @@ class LoginFragment : Fragment(), LoginView {
override
fun
setupCasButtonListener
(
casUrl
:
String
,
casToken
:
String
)
{
button_cas
.
setOnClickListener
{
startActivityForResult
(
context
?.
w
ebViewIntent
(
casUrl
,
casToken
),
REQUEST_CODE_FOR_CAS
)
startActivityForResult
(
context
?.
casW
ebViewIntent
(
casUrl
,
casToken
),
REQUEST_CODE_FOR_CAS
)
activity
?.
overridePendingTransition
(
R
.
anim
.
slide_up
,
R
.
anim
.
hold
)
}
}
...
...
@@ -192,31 +201,46 @@ class LoginFragment : Fragment(), LoginView {
}
override
fun
enableLoginByFacebook
()
{
button_facebook
.
is
Enabled
=
true
button_facebook
.
is
Clickable
=
true
}
override
fun
enableLoginByGithub
()
{
button_github
.
isEnabled
=
true
button_github
.
isClickable
=
true
}
override
fun
setupGithubButtonListener
(
githubUrl
:
String
,
state
:
String
)
{
button_github
.
setOnClickListener
{
// TODO
// startActivityForResult(context?.githubWebViewIntent(url, state), REQUEST_CODE_FOR_OAUTH)
// activity?.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
}
override
fun
enableLoginByGoogle
()
{
button_google
.
is
Enabled
=
true
button_google
.
is
Clickable
=
true
}
override
fun
enableLoginByLinkedin
()
{
button_linkedin
.
is
Enabled
=
true
button_linkedin
.
is
Clickable
=
true
}
override
fun
enableLoginByMeteor
()
{
button_meteor
.
is
Enabled
=
true
button_meteor
.
is
Clickable
=
true
}
override
fun
enableLoginByTwitter
()
{
button_twitter
.
is
Enabled
=
true
button_twitter
.
is
Clickable
=
true
}
override
fun
enableLoginByGitlab
()
{
button_gitlab
.
isEnabled
=
true
button_gitlab
.
isClickable
=
true
}
override
fun
setupGitlabButtonListener
(
gitlabUrl
:
String
,
state
:
String
)
{
button_gitlab
.
setOnClickListener
{
startActivityForResult
(
context
?.
gitlabWebViewIntent
(
gitlabUrl
,
state
),
REQUEST_CODE_FOR_OAUTH
)
activity
?.
overridePendingTransition
(
R
.
anim
.
slide_up
,
R
.
anim
.
hold
)
}
}
override
fun
setupFabListener
()
{
...
...
@@ -253,8 +277,8 @@ class LoginFragment : Fragment(), LoginView {
social_accounts_container
.
postDelayed
({
(
0
..
social_accounts_container
.
childCount
)
.
mapNotNull
{
social_accounts_container
.
getChildAt
(
it
)
as
?
ImageButton
}
.
filter
{
it
.
is
Enabled
}
.
forEach
{
it
.
visibility
=
View
.
VISIBLE
}
.
filter
{
it
.
is
Clickable
}
.
forEach
{
it
.
setVisible
(
true
)
}
},
1000
)
}
...
...
@@ -284,13 +308,10 @@ class LoginFragment : Fragment(), LoginView {
}
private
fun
showThreeSocialAccountsMethods
()
{
var
count
=
0
for
(
i
in
0
..
social_accounts_container
.
childCount
)
{
val
view
=
social_accounts_container
.
getChildAt
(
i
)
as
?
ImageButton
?:
continue
if
(
view
.
isEnabled
&&
count
<
3
)
{
view
.
visibility
=
View
.
VISIBLE
count
++
}
}
(
0
..
social_accounts_container
.
childCount
)
.
mapNotNull
{
social_accounts_container
.
getChildAt
(
it
)
as
?
ImageButton
}
.
filter
{
it
.
isClickable
}
.
take
(
3
)
.
forEach
{
it
.
setVisible
(
true
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt
View file @
e797d903
...
...
@@ -10,6 +10,7 @@ import chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.registerPushToken
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
...
...
@@ -27,6 +28,7 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
factory
:
RocketChatClientFactory
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
settingsInteractor
:
GetSettingsInteractor
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
...
...
@@ -98,9 +100,10 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
private
suspend
fun
registerPushToken
()
{
localRepository
.
get
(
LocalRepository
.
KEY_PUSH_TOKEN
)
?.
let
{
client
.
registerPushToken
(
it
)
client
.
registerPushToken
(
it
,
getAccountsInteractor
.
get
(),
factory
)
}
// TODO: Schedule push token registering when it comes up null
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
private
suspend
fun
saveAccount
(
me
:
Myself
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/AutoCompleteType.kt
View file @
e797d903
...
...
@@ -6,5 +6,5 @@ const val PEOPLE = 0
const
val
ROOMS
=
1
@Retention
(
AnnotationRetention
.
SOURCE
)
@IntDef
(
value
=
[
PEOPLE
,
ROOMS
]
)
@IntDef
(
PEOPLE
,
ROOMS
)
annotation
class
AutoCompleteType
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
e797d903
...
...
@@ -53,7 +53,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
manager
=
factory
.
create
(
currentServer
)
private
val
client
=
manager
.
client
private
var
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
!!
private
var
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
private
val
messagesChannel
=
Channel
<
Message
>()
private
var
chatRoomId
:
String
?
=
null
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/PinnedMessagesPresenter.kt
View file @
e797d903
...
...
@@ -24,7 +24,7 @@ class PinnedMessagesPresenter @Inject constructor(private val view: PinnedMessag
getSettingsInteractor
:
GetSettingsInteractor
)
{
private
val
client
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
private
var
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
!!
private
var
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
private
var
pinnedMessagesListOffset
:
Int
=
0
/**
...
...
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
View file @
e797d903
...
...
@@ -36,7 +36,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
client
=
manager
.
client
private
var
reloadJob
:
Deferred
<
List
<
ChatRoom
>>?
=
null
private
val
settings
=
settingsRepository
.
get
(
currentServer
)
!!
private
val
settings
=
settingsRepository
.
get
(
currentServer
)
private
val
subscriptionsChannel
=
Channel
<
StreamMessage
<
BaseRoom
>>()
private
val
stateChannel
=
Channel
<
State
>()
...
...
@@ -101,21 +101,52 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
private
suspend
fun
usersToChatRooms
(
users
:
List
<
User
>):
List
<
ChatRoom
>
{
return
users
.
map
{
ChatRoom
(
it
.
id
,
RoomType
.
DIRECT_MESSAGE
,
SimpleUser
(
username
=
it
.
username
,
name
=
it
.
name
,
id
=
null
),
it
.
name
?:
""
,
it
.
name
,
false
,
null
,
null
,
null
,
null
,
null
,
false
,
false
,
false
,
0L
,
null
,
0L
,
null
,
client
ChatRoom
(
id
=
it
.
id
,
type
=
RoomType
.
DIRECT_MESSAGE
,
user
=
SimpleUser
(
username
=
it
.
username
,
name
=
it
.
name
,
id
=
null
),
name
=
it
.
name
?:
""
,
fullName
=
it
.
name
,
readonly
=
false
,
updatedAt
=
null
,
timestamp
=
null
,
lastSeen
=
null
,
topic
=
null
,
description
=
null
,
announcement
=
null
,
default
=
false
,
open
=
false
,
alert
=
false
,
unread
=
0L
,
userMenstions
=
null
,
groupMentions
=
0L
,
lastMessage
=
null
,
client
=
client
)
}
}
private
suspend
fun
roomsToChatRooms
(
rooms
:
List
<
Room
>):
List
<
ChatRoom
>
{
return
rooms
.
map
{
ChatRoom
(
it
.
id
,
it
.
type
,
it
.
user
,
it
.
name
?:
""
,
it
.
fullName
,
it
.
readonly
,
it
.
updatedAt
,
null
,
null
,
it
.
topic
,
it
.
announcement
,
false
,
false
,
false
,
0L
,
null
,
0L
,
it
.
lastMessage
,
client
ChatRoom
(
id
=
it
.
id
,
type
=
it
.
type
,
user
=
it
.
user
,
name
=
it
.
name
?:
""
,
fullName
=
it
.
fullName
,
readonly
=
it
.
readonly
,
updatedAt
=
it
.
updatedAt
,
timestamp
=
null
,
lastSeen
=
null
,
topic
=
it
.
topic
,
description
=
it
.
description
,
announcement
=
it
.
announcement
,
default
=
false
,
open
=
false
,
alert
=
false
,
unread
=
0L
,
userMenstions
=
null
,
groupMentions
=
0L
,
lastMessage
=
it
.
lastMessage
,
client
=
client
)
}
}
...
...
@@ -255,6 +286,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
timestamp
,
lastSeen
,
room
.
topic
,
room
.
description
,
room
.
announcement
,
default
,
open
,
...
...
@@ -286,6 +318,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
subscription
.
timestamp
?:
timestamp
,
subscription
.
lastSeen
?:
lastSeen
,
topic
,
description
,
announcement
,
subscription
.
isDefault
,
subscription
.
open
,
...
...
app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
View file @
e797d903
...
...
@@ -157,7 +157,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
// TODO - use a ViewModel Mapper instead of using settings on the adapter
recycler_view
.
adapter
=
ChatRoomsAdapter
(
this
,
settingsRepository
.
get
(
serverInteractor
.
get
()
!!
)
!!
)
{
chatRoom
->
settingsRepository
.
get
(
serverInteractor
.
get
()
!!
))
{
chatRoom
->
presenter
.
loadChatRoom
(
chatRoom
)
}
}
...
...
app/src/main/java/chat/rocket/android/helper/UrlHelper.kt
View file @
e797d903
...
...
@@ -35,6 +35,27 @@ object UrlHelper {
fun
getCasUrl
(
casLoginUrl
:
String
,
serverUrl
:
String
,
token
:
String
):
String
=
removeTrailingSlash
(
casLoginUrl
)
+
"?service="
+
removeTrailingSlash
(
serverUrl
)
+
"/_cas/"
+
token
/**
* Returns the Github Oauth URL.
*
* @param clientId The GitHub client ID.
* @param state An unguessable random string used to protect against forgery attacks.
* @return The Github Oauth URL.
*/
// TODO: Fix github url.
fun
getGithubOauthUrl
(
clientId
:
String
,
state
:
String
):
String
=
"https://github.com/login/oauth/authorize?scope=user:email&client_id=$clientId&state=$state"
/**
* Returns the Gitlab Oauth URL.
*
* @param clientId The Gitlab client ID.
* @param serverUrl The server URL.
* @param state An unguessable random string used to protect against forgery attacks.
* @return The Gitlab Oauth URL.
*/
fun
getGitlabOauthUrl
(
clientId
:
String
,
serverUrl
:
String
,
state
:
String
):
String
=
"https://gitlab.com/oauth/authorize?client_id=$clientId&redirect_uri=${removeTrailingSlash(serverUrl)}/_oauth/gitlab?close&response_type=code&state=$state&scope=read_user"
/**
* Returns the server's Terms of Service URL.
*
...
...
app/src/main/java/chat/rocket/android/util/extensions/Text.kt
View file @
e797d903
...
...
@@ -3,12 +3,15 @@ package chat.rocket.android.util.extensions
import
android.text.Spannable
import
android.text.Spanned
import
android.text.TextUtils
import
android.util.Base64
import
android.util.Patterns
import
android.widget.EditText
import
android.widget.TextView
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.android.widget.emoji.EmojiTypefaceSpan
import
org.json.JSONObject
import
ru.noties.markwon.Markwon
import
java.net.URLDecoder
import
java.security.SecureRandom
fun
String
.
ifEmpty
(
value
:
String
):
String
{
...
...
@@ -33,7 +36,23 @@ fun EditText.erase() {
}
}
fun
String
.
isEmailValid
():
Boolean
=
Patterns
.
EMAIL_ADDRESS
.
matcher
(
this
).
matches
()
fun
String
.
isEmail
():
Boolean
=
Patterns
.
EMAIL_ADDRESS
.
matcher
(
this
).
matches
()
fun
String
.
encodeToBase64
():
String
{
return
Base64
.
encodeToString
(
this
.
toByteArray
(
charset
(
"UTF-8"
)),
Base64
.
NO_WRAP
)
}
fun
String
.
decodeFromBase64
():
String
{
return
Base64
.
decode
(
this
,
Base64
.
DEFAULT
).
toString
(
charset
(
"UTF-8"
))
}
fun
String
.
decodeUrl
():
String
{
return
URLDecoder
.
decode
(
this
,
"UTF-8"
)
}
fun
String
.
toJsonObject
():
JSONObject
{
return
JSONObject
(
this
)
}
fun
generateRandomString
(
stringLength
:
Int
):
String
{
val
base
=
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
...
...
app/src/main/java/chat/rocket/android/webview/cas/ui/CasWebViewActivity.kt
View file @
e797d903
...
...
@@ -13,7 +13,7 @@ import chat.rocket.android.R
import
kotlinx.android.synthetic.main.activity_web_view.*
import
kotlinx.android.synthetic.main.app_bar.*
fun
Context
.
w
ebViewIntent
(
webPageUrl
:
String
,
casToken
:
String
):
Intent
{
fun
Context
.
casW
ebViewIntent
(
webPageUrl
:
String
,
casToken
:
String
):
Intent
{
return
Intent
(
this
,
CasWebViewActivity
::
class
.
java
).
apply
{
putExtra
(
INTENT_WEB_PAGE_URL
,
webPageUrl
)
putExtra
(
INTENT_CAS_TOKEN
,
casToken
)
...
...
@@ -21,7 +21,7 @@ fun Context.webViewIntent(webPageUrl: String, casToken: String): Intent {
}
private
const
val
INTENT_WEB_PAGE_URL
=
"web_page_url"
private
const
val
INTENT_CAS_TOKEN
=
"cas_token"
const
val
INTENT_CAS_TOKEN
=
"cas_token"
class
CasWebViewActivity
:
AppCompatActivity
()
{
private
lateinit
var
webPageUrl
:
String
...
...
@@ -49,14 +49,14 @@ class CasWebViewActivity : AppCompatActivity() {
if
(
web_view
.
canGoBack
())
{
web_view
.
goBack
()
}
else
{
finishActivity
(
false
)
closeView
(
)
}
}
private
fun
setupToolbar
()
{
toolbar
.
title
=
getString
(
R
.
string
.
title_authentication
)
toolbar
.
setNavigationIcon
(
R
.
drawable
.
ic_close_white_24dp
)
toolbar
.
setNavigationOnClickListener
{
finishActivity
(
false
)
}
toolbar
.
setNavigationOnClickListener
{
closeView
(
)
}
}
@SuppressLint
(
"SetJavaScriptEnabled"
)
...
...
@@ -64,16 +64,16 @@ class CasWebViewActivity : AppCompatActivity() {
web_view
.
settings
.
javaScriptEnabled
=
true
web_view
.
webViewClient
=
object
:
WebViewClient
()
{
override
fun
onPageStarted
(
view
:
WebView
,
url
:
String
,
favicon
:
Bitmap
?)
{
// The user
can be already
logged in the CAS, so check if the URL contains the "ticket" word
// (that means
he/she is successful authenticated and we don't need to wait until the page is finished
.
// The user
may have already been
logged in the CAS, so check if the URL contains the "ticket" word
// (that means
the user is successful authenticated and we don't need to wait until the page is fully loaded)
.
if
(
url
.
contains
(
"ticket"
))
{
finishActivity
(
true
)
closeView
(
Activity
.
RESULT_OK
)
}
}
override
fun
onPageFinished
(
view
:
WebView
,
url
:
String
)
{
if
(
url
.
contains
(
"ticket"
))
{
finishActivity
(
true
)
closeView
(
Activity
.
RESULT_OK
)
}
else
{
view_loading
.
hide
()
}
...
...
@@ -82,13 +82,9 @@ class CasWebViewActivity : AppCompatActivity() {
web_view
.
loadUrl
(
webPageUrl
)
}
private
fun
finishActivity
(
setResultOk
:
Boolean
)
{
if
(
setResultOk
)
{
setResult
(
Activity
.
RESULT_OK
,
Intent
().
putExtra
(
INTENT_CAS_TOKEN
,
casToken
))
finish
()
}
else
{
super
.
onBackPressed
()
}
private
fun
closeView
(
activityResult
:
Int
=
Activity
.
RESULT_CANCELED
)
{
setResult
(
activityResult
,
Intent
().
putExtra
(
INTENT_CAS_TOKEN
,
casToken
))
finish
()
overridePendingTransition
(
R
.
anim
.
hold
,
R
.
anim
.
slide_down
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/webview/gitlab/ui/GitlabWebViewActivity.kt
0 → 100644
View file @
e797d903
package
chat.rocket.android.webview.gitlab.ui
import
android.annotation.SuppressLint
import
android.app.Activity
import
android.content.Context
import
android.content.Intent
import
android.os.Bundle
import
android.support.v7.app.AppCompatActivity
import
android.webkit.WebView
import
android.webkit.WebViewClient
import
androidx.net.toUri
import
chat.rocket.android.R
import
chat.rocket.android.util.extensions.decodeUrl
import
chat.rocket.android.util.extensions.toJsonObject
import
kotlinx.android.synthetic.main.activity_web_view.*
import
kotlinx.android.synthetic.main.app_bar.*
import
org.json.JSONObject
fun
Context
.
gitlabWebViewIntent
(
webPageUrl
:
String
,
state
:
String
):
Intent
{
return
Intent
(
this
,
GitlabWebViewActivity
::
class
.
java
).
apply
{
putExtra
(
INTENT_WEB_PAGE_URL
,
webPageUrl
)
putExtra
(
INTENT_STATE
,
state
)
}
}
private
const
val
INTENT_WEB_PAGE_URL
=
"web_page_url"
private
const
val
INTENT_STATE
=
"state"
private
const
val
JSON_CREDENTIAL_TOKEN
=
"credentialToken"
private
const
val
JSON_CREDENTIAL_SECRET
=
"credentialSecret"
const
val
INTENT_OAUTH_CREDENTIAL_TOKEN
=
"credential_token"
const
val
INTENT_OAUTH_CREDENTIAL_SECRET
=
"credential_secret"
// Shows a WebView to the user authenticate with your Gitlab credentials.
class
GitlabWebViewActivity
:
AppCompatActivity
()
{
private
lateinit
var
webPageUrl
:
String
private
lateinit
var
state
:
String
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_web_view
)
webPageUrl
=
intent
.
getStringExtra
(
INTENT_WEB_PAGE_URL
)
requireNotNull
(
webPageUrl
)
{
"no web_page_url provided in Intent extras"
}
state
=
intent
.
getStringExtra
(
INTENT_STATE
)
requireNotNull
(
state
)
{
"no state provided in Intent extras"
}
setupToolbar
()
}
override
fun
onResume
()
{
super
.
onResume
()
setupWebView
()
}
override
fun
onBackPressed
()
{
if
(
web_view
.
canGoBack
())
{
web_view
.
goBack
()
}
else
{
closeView
()
}
}
private
fun
setupToolbar
()
{
toolbar
.
title
=
getString
(
R
.
string
.
title_authentication
)
toolbar
.
setNavigationIcon
(
R
.
drawable
.
ic_close_white_24dp
)
toolbar
.
setNavigationOnClickListener
{
closeView
()
}
}
@SuppressLint
(
"SetJavaScriptEnabled"
)
private
fun
setupWebView
()
{
web_view
.
settings
.
javaScriptEnabled
=
true
web_view
.
webViewClient
=
object
:
WebViewClient
()
{
override
fun
onPageFinished
(
view
:
WebView
,
url
:
String
)
{
if
(
url
.
contains
(
JSON_CREDENTIAL_TOKEN
)
&&
url
.
contains
(
JSON_CREDENTIAL_SECRET
))
{
if
(
isStateValid
(
url
))
{
val
jsonResult
=
url
.
decodeUrl
()
.
substringAfter
(
"#"
)
.
toJsonObject
()
val
credentialToken
=
getCredentialToken
(
jsonResult
)
val
credentialSecret
=
getCredentialSecret
(
jsonResult
)
if
(
credentialToken
.
isNotEmpty
()
&&
credentialSecret
.
isNotEmpty
())
{
closeView
(
Activity
.
RESULT_OK
,
credentialToken
,
credentialSecret
)
}
}
}
view_loading
.
hide
()
}
}
web_view
.
loadUrl
(
webPageUrl
)
}
// If the states matches, then try to get the code, otherwise the request was created by a third party and the process should be aborted.
private
fun
isStateValid
(
url
:
String
):
Boolean
=
url
.
substringBefore
(
"#"
).
toUri
().
getQueryParameter
(
INTENT_STATE
)
==
state
private
fun
getCredentialToken
(
json
:
JSONObject
):
String
=
json
.
optString
(
JSON_CREDENTIAL_TOKEN
)
private
fun
getCredentialSecret
(
json
:
JSONObject
):
String
=
json
.
optString
(
JSON_CREDENTIAL_SECRET
)
private
fun
closeView
(
activityResult
:
Int
=
Activity
.
RESULT_CANCELED
,
credentialToken
:
String
?
=
null
,
credentialSecret
:
String
?
=
null
)
{
setResult
(
activityResult
,
Intent
().
putExtra
(
INTENT_OAUTH_CREDENTIAL_TOKEN
,
credentialToken
).
putExtra
(
INTENT_OAUTH_CREDENTIAL_SECRET
,
credentialSecret
))
finish
()
overridePendingTransition
(
R
.
anim
.
hold
,
R
.
anim
.
slide_down
)
}
}
\ No newline at end of file
app/src/main/res/layout/fragment_authentication_log_in.xml
View file @
e797d903
...
...
@@ -113,6 +113,7 @@
android:layout_width=
"290dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"16dp"
android:clickable=
"false"
android:contentDescription=
"@string/msg_content_description_log_in_using_facebook"
android:foreground=
"?android:attr/selectableItemBackgroundBorderless"
android:src=
"@drawable/ic_facebook"
...
...
@@ -124,6 +125,7 @@
android:layout_width=
"290dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"16dp"
android:clickable=
"false"
android:contentDescription=
"@string/msg_content_description_log_in_using_github"
android:foreground=
"?android:attr/selectableItemBackgroundBorderless"
android:src=
"@drawable/ic_github"
...
...
@@ -135,6 +137,7 @@
android:layout_width=
"290dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"16dp"
android:clickable=
"false"
android:contentDescription=
"@string/msg_content_description_log_in_using_google"
android:foreground=
"?android:attr/selectableItemBackground"
android:src=
"@drawable/ic_google"
...
...
@@ -146,6 +149,7 @@
android:layout_width=
"290dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"16dp"
android:clickable=
"false"
android:contentDescription=
"@string/msg_content_description_log_in_using_linkedin"
android:foreground=
"?android:attr/selectableItemBackgroundBorderless"
android:src=
"@drawable/ic_linkedin"
...
...
@@ -157,6 +161,7 @@
android:layout_width=
"290dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"16dp"
android:clickable=
"false"
android:contentDescription=
"@string/msg_content_description_log_in_using_meteor"
android:foreground=
"?android:attr/selectableItemBackgroundBorderless"
android:src=
"@drawable/ic_meteor"
...
...
@@ -168,6 +173,7 @@
android:layout_width=
"290dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"16dp"
android:clickable=
"false"
android:contentDescription=
"@string/msg_content_description_log_in_using_twitter"
android:foreground=
"?android:attr/selectableItemBackgroundBorderless"
android:src=
"@drawable/ic_twitter"
...
...
@@ -179,6 +185,7 @@
android:layout_width=
"290dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"16dp"
android:clickable=
"false"
android:contentDescription=
"@string/msg_content_description_log_in_using_gitlab"
android:foreground=
"?android:attr/selectableItemBackgroundBorderless"
android:src=
"@drawable/ic_gitlab"
...
...
gradle/wrapper/gradle-wrapper.properties
View file @
e797d903
...
...
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath
=
wrapper/dists
zipStoreBase
=
GRADLE_USER_HOME
zipStorePath
=
wrapper/dists
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-4.
1
-all.zip
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-4.
6
-all.zip
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