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
c8493fbb
Commit
c8493fbb
authored
Jan 18, 2017
by
Gabriel Engel
Committed by
GitHub
Jan 18, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #153 from RocketChat/fix/validate-server-with-insecure-connection
App connects to insecure servers.
parents
70b0c82e
0d252ef3
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
246 additions
and
61 deletions
+246
-61
DDPClientWrapper.java
...c/main/java/chat/rocket/android/api/DDPClientWrapper.java
+4
-2
DefaultServerPolicyApi.java
.../chat/rocket/android/api/rest/DefaultServerPolicyApi.java
+87
-0
Response.java
app/src/main/java/chat/rocket/android/api/rest/Response.java
+25
-0
ServerPolicyApi.java
...in/java/chat/rocket/android/api/rest/ServerPolicyApi.java
+15
-0
InputHostnameFragment.java
...android/fragment/server_config/InputHostnameFragment.java
+37
-14
ServerPolicyApiValidationHelper.java
...ocket/android/helper/ServerPolicyApiValidationHelper.java
+24
-0
ServerPolicyHelper.java
...n/java/chat/rocket/android/helper/ServerPolicyHelper.java
+42
-44
ServerConfig.java
...src/main/java/chat/rocket/android/model/ServerConfig.java
+10
-0
RocketChatWebSocketThread.java
...hat/rocket/android/service/RocketChatWebSocketThread.java
+1
-1
strings.xml
app/src/main/res/values/strings.xml
+1
-0
No files found.
app/src/main/java/chat/rocket/android/api/DDPClientWrapper.java
View file @
c8493fbb
...
...
@@ -38,8 +38,10 @@ public class DDPClientWrapper {
/**
* Connect to WebSocket server with DDP client.
*/
public
Task
<
DDPClientCallback
.
Connect
>
connect
(
@Nullable
String
session
)
{
return
ddpClient
.
connect
(
"wss://"
+
hostname
+
"/websocket"
,
session
);
public
Task
<
DDPClientCallback
.
Connect
>
connect
(
@Nullable
String
session
,
boolean
usesSecureConnection
)
{
final
String
protocol
=
usesSecureConnection
?
"wss://"
:
"ws://"
;
return
ddpClient
.
connect
(
protocol
+
hostname
+
"/websocket"
,
session
);
}
/**
...
...
app/src/main/java/chat/rocket/android/api/rest/DefaultServerPolicyApi.java
0 → 100644
View file @
c8493fbb
package
chat
.
rocket
.
android
.
api
.
rest
;
import
android.support.annotation.NonNull
;
import
org.json.JSONObject
;
import
java.io.IOException
;
import
okhttp3.Call
;
import
okhttp3.OkHttpClient
;
import
okhttp3.Request
;
import
okhttp3.ResponseBody
;
import
rx.Emitter
;
import
rx.Observable
;
public
class
DefaultServerPolicyApi
implements
ServerPolicyApi
{
private
static
final
String
API_INFO_PATH
=
"/api/info"
;
private
final
OkHttpClient
client
;
private
final
String
host
;
public
DefaultServerPolicyApi
(
@NonNull
OkHttpClient
client
,
@NonNull
String
host
)
{
this
.
client
=
client
;
this
.
host
=
host
;
}
@Override
public
Observable
<
Response
<
JSONObject
>>
getApiInfoSecurely
()
{
return
getApiInfo
(
SECURE_PROTOCOL
);
}
@Override
public
Observable
<
Response
<
JSONObject
>>
getApiInfoInsecurely
()
{
return
getApiInfo
(
INSECURE_PROTOCOL
);
}
private
Observable
<
Response
<
JSONObject
>>
getApiInfo
(
@NonNull
String
protocol
)
{
return
Observable
.
fromEmitter
(
responseEmitter
->
{
final
Call
call
=
client
.
newCall
(
createRequest
(
protocol
));
call
.
enqueue
(
getOkHttpCallback
(
responseEmitter
,
protocol
));
responseEmitter
.
setCancellation
(
call:
:
cancel
);
},
Emitter
.
BackpressureMode
.
LATEST
);
}
private
Request
createRequest
(
@NonNull
String
protocol
)
{
return
new
Request
.
Builder
()
.
url
(
protocol
+
host
+
API_INFO_PATH
)
.
get
()
.
build
();
}
private
okhttp3
.
Callback
getOkHttpCallback
(
@NonNull
Emitter
<
Response
<
JSONObject
>>
emitter
,
@NonNull
String
protocol
)
{
return
new
okhttp3
.
Callback
()
{
@Override
public
void
onFailure
(
Call
call
,
IOException
ioException
)
{
emitter
.
onError
(
ioException
);
}
@Override
public
void
onResponse
(
Call
call
,
okhttp3
.
Response
response
)
throws
IOException
{
if
(!
response
.
isSuccessful
())
{
emitter
.
onNext
(
new
Response
<>(
false
,
protocol
,
null
));
emitter
.
onCompleted
();
return
;
}
final
ResponseBody
body
=
response
.
body
();
if
(
body
==
null
||
body
.
contentLength
()
==
0
)
{
emitter
.
onNext
(
new
Response
<>(
false
,
protocol
,
null
));
emitter
.
onCompleted
();
return
;
}
try
{
emitter
.
onNext
(
new
Response
<>(
true
,
protocol
,
new
JSONObject
(
body
.
string
())));
}
catch
(
Exception
e
)
{
emitter
.
onNext
(
new
Response
<>(
false
,
protocol
,
null
));
}
emitter
.
onCompleted
();
}
};
}
}
app/src/main/java/chat/rocket/android/api/rest/Response.java
0 → 100644
View file @
c8493fbb
package
chat
.
rocket
.
android
.
api
.
rest
;
public
class
Response
<
T
>
{
private
final
boolean
successful
;
private
final
String
protocol
;
private
final
T
data
;
public
Response
(
boolean
successful
,
String
protocol
,
T
data
)
{
this
.
successful
=
successful
;
this
.
protocol
=
protocol
;
this
.
data
=
data
;
}
public
boolean
isSuccessful
()
{
return
successful
;
}
public
String
getProtocol
()
{
return
protocol
;
}
public
T
getData
()
{
return
data
;
}
}
app/src/main/java/chat/rocket/android/api/rest/ServerPolicyApi.java
0 → 100644
View file @
c8493fbb
package
chat
.
rocket
.
android
.
api
.
rest
;
import
org.json.JSONObject
;
import
rx.Observable
;
public
interface
ServerPolicyApi
{
String
SECURE_PROTOCOL
=
"https://"
;
String
INSECURE_PROTOCOL
=
"http://"
;
Observable
<
Response
<
JSONObject
>>
getApiInfoSecurely
();
Observable
<
Response
<
JSONObject
>>
getApiInfoInsecurely
();
}
app/src/main/java/chat/rocket/android/fragment/server_config/InputHostnameFragment.java
View file @
c8493fbb
...
...
@@ -7,13 +7,19 @@ import org.json.JSONObject;
import
chat.rocket.android.BuildConfig
;
import
chat.rocket.android.R
;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.android.api.rest.DefaultServerPolicyApi
;
import
chat.rocket.android.api.rest.ServerPolicyApi
;
import
chat.rocket.android.helper.LogcatIfError
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
chat.rocket.android.helper.ServerPolicyApiValidationHelper
;
import
chat.rocket.android.helper.ServerPolicyHelper
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.model.ServerConfig
;
import
chat.rocket.android.realm_helper.RealmObjectObserver
;
import
chat.rocket.android.realm_helper.RealmStore
;
import
rx.Subscription
;
import
rx.android.schedulers.AndroidSchedulers
;
import
rx.schedulers.Schedulers
;
/**
* Input server host.
...
...
@@ -24,6 +30,8 @@ public class InputHostnameFragment extends AbstractServerConfigFragment {
realm
.
where
(
ServerConfig
.
class
).
equalTo
(
ServerConfig
.
ID
,
serverConfigId
))
.
setOnUpdateListener
(
this
::
onRenderServerConfig
);
Subscription
serverPolicySubscription
;
public
InputHostnameFragment
()
{
}
...
...
@@ -49,24 +57,38 @@ public class InputHostnameFragment extends AbstractServerConfigFragment {
private
void
handleConnect
()
{
final
String
hostname
=
ServerPolicyHelper
.
enforceHostname
(
getHostname
());
ServerPolicyHelper
.
isApiVersionValid
(
OkHttpHelper
.
getClientForUploadFile
(),
hostname
,
new
ServerPolicyHelper
.
Callback
()
{
@Override
public
void
isValid
()
{
getActivity
().
runOnUiThread
(()
->
onServerValid
(
hostname
));
}
@Override
public
void
isNotValid
()
{
getActivity
().
runOnUiThread
(()
->
showError
(
getString
(
R
.
string
.
input_hostname_invalid_server_message
)));
}
});
final
ServerPolicyApi
serverPolicyApi
=
new
DefaultServerPolicyApi
(
OkHttpHelper
.
getClientForUploadFile
(),
hostname
);
final
ServerPolicyApiValidationHelper
validationHelper
=
new
ServerPolicyApiValidationHelper
(
serverPolicyApi
);
if
(
serverPolicySubscription
!=
null
)
{
serverPolicySubscription
.
unsubscribe
();
}
serverPolicySubscription
=
ServerPolicyHelper
.
isApiVersionValid
(
validationHelper
)
.
subscribeOn
(
Schedulers
.
io
())
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
serverValidation
->
{
if
(
serverValidation
.
isValid
())
{
onServerValid
(
hostname
,
serverValidation
.
usesSecureConnection
());
}
else
{
showError
(
getString
(
R
.
string
.
input_hostname_invalid_server_message
));
}
},
throwable
->
{
showError
(
getString
(
R
.
string
.
connection_error_try_later
));
});
}
@Override
public
void
onDestroyView
()
{
serverConfigObserver
.
unsub
();
if
(
serverPolicySubscription
!=
null
)
{
serverPolicySubscription
.
unsubscribe
();
}
super
.
onDestroyView
();
}
...
...
@@ -76,7 +98,7 @@ public class InputHostnameFragment extends AbstractServerConfigFragment {
return
TextUtils
.
or
(
TextUtils
.
or
(
editor
.
getText
(),
editor
.
getHint
()),
""
).
toString
();
}
private
void
onServerValid
(
final
String
hostname
)
{
private
void
onServerValid
(
final
String
hostname
,
boolean
usesSecureConnection
)
{
RocketChatCache
.
get
(
getContext
()).
edit
()
.
putString
(
RocketChatCache
.
KEY_SELECTED_SERVER_CONFIG_ID
,
serverConfigId
)
.
apply
();
...
...
@@ -87,6 +109,7 @@ public class InputHostnameFragment extends AbstractServerConfigFragment {
.
put
(
ServerConfig
.
HOSTNAME
,
hostname
)
.
put
(
ServerConfig
.
ERROR
,
JSONObject
.
NULL
)
.
put
(
ServerConfig
.
SESSION
,
JSONObject
.
NULL
)
.
put
(
ServerConfig
.
SECURE_CONNECTION
,
usesSecureConnection
)
.
put
(
ServerConfig
.
STATE
,
ServerConfig
.
STATE_READY
)))
.
continueWith
(
new
LogcatIfError
());
}
...
...
app/src/main/java/chat/rocket/android/helper/ServerPolicyApiValidationHelper.java
0 → 100644
View file @
c8493fbb
package
chat
.
rocket
.
android
.
helper
;
import
android.support.annotation.NonNull
;
import
chat.rocket.android.api.rest.ServerPolicyApi
;
import
rx.Observable
;
public
class
ServerPolicyApiValidationHelper
{
private
final
ServerPolicyApi
serverPolicyApi
;
public
ServerPolicyApiValidationHelper
(
@NonNull
ServerPolicyApi
serverPolicyApi
)
{
this
.
serverPolicyApi
=
serverPolicyApi
;
}
public
Observable
<
ServerPolicyHelper
.
ServerInfo
>
getApiVersion
()
{
return
serverPolicyApi
.
getApiInfoSecurely
()
.
onErrorResumeNext
(
serverPolicyApi
.
getApiInfoInsecurely
())
.
map
(
response
->
new
ServerPolicyHelper
.
ServerInfo
(
response
.
getProtocol
().
equals
(
ServerPolicyApi
.
SECURE_PROTOCOL
),
response
.
getData
()
));
}
}
app/src/main/java/chat/rocket/android/helper/ServerPolicyHelper.java
View file @
c8493fbb
...
...
@@ -4,17 +4,11 @@ import android.support.annotation.NonNull;
import
org.json.JSONObject
;
import
java.io.IOException
;
import
okhttp3.Call
;
import
okhttp3.OkHttpClient
;
import
okhttp3.Request
;
import
okhttp3.Response
;
import
okhttp3.ResponseBody
;
import
rx.Observable
;
public
class
ServerPolicyHelper
{
private
static
final
String
DEFAULT_HOST
=
".rocket.chat"
;
private
static
final
String
API_INFO_PATH
=
"/api/info"
;
private
static
final
String
VERSION_PROPERTY
=
"version"
;
public
static
String
enforceHostname
(
String
hostname
)
{
...
...
@@ -25,36 +19,12 @@ public class ServerPolicyHelper {
return
removeTrailingSlash
(
removeProtocol
(
enforceDefaultHost
(
hostname
)));
}
public
static
void
isApiVersionValid
(
@NonNull
OkHttpClient
client
,
@NonNull
String
host
,
@NonNull
Callback
callback
)
{
Request
request
;
try
{
request
=
new
Request
.
Builder
()
.
url
(
"https://"
+
host
+
API_INFO_PATH
)
.
get
()
.
build
();
}
catch
(
Exception
e
)
{
callback
.
isNotValid
();
return
;
}
client
.
newCall
(
request
).
enqueue
(
new
okhttp3
.
Callback
()
{
@Override
public
void
onFailure
(
Call
call
,
IOException
exception
)
{
// some connection error
callback
.
isNotValid
();
}
@Override
public
void
onResponse
(
Call
call
,
Response
response
)
throws
IOException
{
if
(!
response
.
isSuccessful
()
||
!
isValid
(
response
.
body
()))
{
callback
.
isNotValid
();
return
;
}
callback
.
isValid
();
}
});
public
static
Observable
<
ServerValidation
>
isApiVersionValid
(
@NonNull
ServerPolicyApiValidationHelper
serverPolicyApiValidationHelper
)
{
return
serverPolicyApiValidationHelper
.
getApiVersion
()
.
map
(
serverInfo
->
new
ServerValidation
(
isValid
(
serverInfo
.
getApiInfo
()),
serverInfo
.
usesSecureConnection
()));
}
@NonNull
...
...
@@ -80,14 +50,12 @@ public class ServerPolicyHelper {
return
hostname
.
replaceAll
(
"/+$"
,
""
);
}
private
static
boolean
isValid
(
ResponseBody
body
)
{
if
(
body
==
null
||
body
.
contentLength
()
==
0
)
{
private
static
boolean
isValid
(
JSONObject
jsonObject
)
{
if
(
jsonObject
==
null
)
{
return
false
;
}
try
{
final
JSONObject
jsonObject
=
new
JSONObject
(
body
.
string
());
return
jsonObject
.
has
(
VERSION_PROPERTY
)
&&
isVersionValid
(
jsonObject
.
getString
(
VERSION_PROPERTY
));
}
catch
(
Exception
e
)
{
...
...
@@ -104,9 +72,39 @@ public class ServerPolicyHelper {
return
versionParts
.
length
>=
3
&&
Integer
.
parseInt
(
versionParts
[
1
])
>=
49
;
}
public
interface
Callback
{
void
isValid
();
public
static
class
ServerInfo
{
private
final
boolean
secureConnection
;
private
final
JSONObject
apiInfo
;
public
ServerInfo
(
boolean
secureConnection
,
JSONObject
apiInfo
)
{
this
.
secureConnection
=
secureConnection
;
this
.
apiInfo
=
apiInfo
;
}
public
boolean
usesSecureConnection
()
{
return
secureConnection
;
}
public
JSONObject
getApiInfo
()
{
return
apiInfo
;
}
}
public
static
class
ServerValidation
{
private
final
boolean
valid
;
private
final
boolean
secureConnection
;
void
isNotValid
();
public
ServerValidation
(
boolean
valid
,
boolean
secureConnection
)
{
this
.
valid
=
valid
;
this
.
secureConnection
=
secureConnection
;
}
public
boolean
isValid
()
{
return
valid
;
}
public
boolean
usesSecureConnection
()
{
return
secureConnection
;
}
}
}
app/src/main/java/chat/rocket/android/model/ServerConfig.java
View file @
c8493fbb
...
...
@@ -19,6 +19,7 @@ public class ServerConfig extends RealmObject {
public
static
final
String
HOSTNAME
=
"hostname"
;
public
static
final
String
STATE
=
"state"
;
public
static
final
String
SESSION
=
"session"
;
public
static
final
String
SECURE_CONNECTION
=
"secureConnection"
;
public
static
final
String
ERROR
=
"error"
;
public
static
final
int
STATE_READY
=
0
;
...
...
@@ -30,6 +31,7 @@ public class ServerConfig extends RealmObject {
private
String
hostname
;
private
int
state
;
private
String
session
;
private
boolean
secureConnection
;
private
String
error
;
/**
...
...
@@ -93,6 +95,14 @@ public class ServerConfig extends RealmObject {
this
.
session
=
session
;
}
public
boolean
usesSecureConnection
()
{
return
secureConnection
;
}
public
void
setSecureConnection
(
boolean
usesSecureConnection
)
{
this
.
secureConnection
=
usesSecureConnection
;
}
public
String
getError
()
{
return
error
;
}
...
...
app/src/main/java/chat/rocket/android/service/RocketChatWebSocketThread.java
View file @
c8493fbb
...
...
@@ -170,7 +170,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
realm
.
where
(
ServerConfig
.
class
).
equalTo
(
ServerConfig
.
ID
,
serverConfigId
).
findFirst
());
prepareWebSocket
(
config
.
getHostname
());
return
ddpClient
.
connect
(
config
.
getSession
())
return
ddpClient
.
connect
(
config
.
getSession
()
,
config
.
usesSecureConnection
()
)
.
onSuccessTask
(
task
->
{
final
String
session
=
task
.
getResult
().
session
;
defaultRealm
.
executeTransaction
(
realm
->
...
...
app/src/main/res/values/strings.xml
View file @
c8493fbb
...
...
@@ -44,6 +44,7 @@
<string
name=
"video_upload_message_spec_title"
>
Attach video
</string>
<string
name=
"input_hostname_invalid_server_message"
>
Invalid server version
</string>
<string
name=
"connection_error_try_later"
>
There\'s a connection error. Please try later.
</string>
<string
name=
"version_info_text"
>
Version: %s
</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