Commit 96305dea authored by Valere's avatar Valere

Jitsi Widget Permissions

parent 219b14fb
......@@ -6,9 +6,10 @@ MatrixSdk 🚀:
Features ✨:
- Privacy / Room Widget permissions (#3378)
- Privacy / Widget Permission for jitsi widgets (#3391)
Improvementss 🙌:
-
- Jitsi / Use mx display name in Jitsi conf
Other changes:
- Add User-Interactive Auth to /account/3pid/add (#3333)
......
......@@ -31,12 +31,14 @@ import org.jetbrains.annotations.Nullable;
import org.jitsi.meet.sdk.JitsiMeetActivityDelegate;
import org.jitsi.meet.sdk.JitsiMeetActivityInterface;
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
import org.jitsi.meet.sdk.JitsiMeetUserInfo;
import org.jitsi.meet.sdk.JitsiMeetView;
import org.jitsi.meet.sdk.JitsiMeetViewListener;
import org.matrix.androidsdk.MXSession;
import org.matrix.androidsdk.core.Log;
import org.matrix.androidsdk.data.Room;
import java.net.URL;
import java.util.Map;
import butterknife.BindView;
......@@ -65,7 +67,7 @@ public class JitsiCallActivity extends VectorAppCompatActivity implements JitsiM
/**
* Base server URL
*/
private static final String JITSI_SERVER_URL = "https://jitsi.riot.im/";
public static final String JITSI_SERVER_URL = "https://jitsi.riot.im/";
// the jitsi view
private JitsiMeetView mJitsiView;
......@@ -156,8 +158,22 @@ public class JitsiCallActivity extends VectorAppCompatActivity implements JitsiM
*/
private void loadURL() {
try {
JitsiMeetUserInfo userInfo = new JitsiMeetUserInfo();
userInfo.setDisplayName(mSession.getMyUser().displayname);
try {
String avatarUrl = mSession.getMyUser().avatar_url;
if (avatarUrl != null) {
String downloadableUrl = mSession.getContentManager().getDownloadableUrl(avatarUrl, false);
if (downloadableUrl != null) {
userInfo.setAvatar(new URL(downloadableUrl));
}
}
} catch (Exception e) {
//nop
}
JitsiMeetConferenceOptions jitsiMeetConferenceOptions = new JitsiMeetConferenceOptions.Builder()
.setVideoMuted(!mIsVideoCall)
.setUserInfo(userInfo)
// Configure the title of the screen
// TODO config.putString("callDisplayName", mRoom.getRoomDisplayName(this));
.setRoom(mCallUrl)
......
......@@ -118,6 +118,7 @@ import im.vector.features.hhs.ResourceLimitEventListener;
import im.vector.fragments.VectorMessageListFragment;
import im.vector.fragments.VectorReadReceiptsDialogFragment;
import im.vector.fragments.VectorUnknownDevicesFragment;
import im.vector.fragments.roomwidgets.RoomWidgetPermissionBottomSheet;
import im.vector.listeners.IMessagesAdapterActionsListener;
import im.vector.ui.themes.ThemeUtils;
import im.vector.util.CallsManager;
......@@ -128,6 +129,7 @@ import im.vector.util.PreferencesManager;
import im.vector.util.ReadMarkerManager;
import im.vector.util.RoomUtils;
import im.vector.util.SlashCommandsParser;
import im.vector.util.UrlUtilKt;
import im.vector.util.VectorMarkdownParser;
import im.vector.util.VectorRoomMediasSender;
import im.vector.util.VectorUtils;
......@@ -138,6 +140,7 @@ import im.vector.view.VectorOngoingConferenceCallView;
import im.vector.view.VectorPendingCallView;
import im.vector.widgets.Widget;
import im.vector.widgets.WidgetsManager;
import kotlin.Unit;
/**
* Displays a single room with messages.
......@@ -924,7 +927,7 @@ public class VectorRoomActivity extends MXCActionBarActivity implements
}
new AlertDialog.Builder(VectorRoomActivity.this)
.setItems(widgetNames.toArray(CharSequences), new DialogInterface.OnClickListener() {
.setItems(widgetNames.toArray(CharSequences), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int n) {
d.cancel();
......@@ -1765,10 +1768,31 @@ public class VectorRoomActivity extends MXCActionBarActivity implements
.setPositiveButton(R.string.ok, null)
.show();
} else {
final Intent intent = new Intent(this, JitsiCallActivity.class);
intent.putExtra(JitsiCallActivity.EXTRA_WIDGET_ID, widget);
intent.putExtra(JitsiCallActivity.EXTRA_ENABLE_VIDEO, aIsVideoCall);
startActivity(intent);
//Here check native widget perm
String domain = UrlUtilKt.extractDomain(JitsiCallActivity.JITSI_SERVER_URL);
if (domain == null) return; //display a toast?
boolean isAllowed = mSession.getIntegrationManager().isVideoConfDomainAllowed(domain);
if (isAllowed) {
final Intent intent = new Intent(this, JitsiCallActivity.class);
intent.putExtra(JitsiCallActivity.EXTRA_WIDGET_ID, widget);
intent.putExtra(JitsiCallActivity.EXTRA_ENABLE_VIDEO, aIsVideoCall);
startActivity(intent);
} else {
//we need to prompt for permissions
RoomWidgetPermissionBottomSheet bs = RoomWidgetPermissionBottomSheet.Companion
.newInstance(mSession.getMyUserId(), widget);
bs.setOnFinish((accepted) -> {
if (accepted) {
final Intent intent = new Intent(this, JitsiCallActivity.class);
intent.putExtra(JitsiCallActivity.EXTRA_WIDGET_ID, widget);
intent.putExtra(JitsiCallActivity.EXTRA_ENABLE_VIDEO, aIsVideoCall);
startActivity(intent);
}
return Unit.INSTANCE;
});
bs.show(getSupportFragmentManager(), "JitsyPerm");
}
}
}
......
......@@ -65,7 +65,11 @@ class WidgetActivity : VectorAppCompatActivity() {
//already there
} else {
RoomWidgetPermissionBottomSheet
.newInstance(viewModel.session!!.myUserId, viewModel.widget)
.newInstance(viewModel.session!!.myUserId, viewModel.widget).apply {
onFinish = { accepted ->
if (!accepted) finish()
}
}
.show(supportFragmentManager, FRAGMENT_TAG_PERMISSION)
}
}
......
......@@ -26,7 +26,6 @@ import android.widget.TextView
import butterknife.BindView
import butterknife.OnClick
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.R
......@@ -53,8 +52,8 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() {
@BindView(R.id.bottom_sheet_widget_permission_owner_avatar)
lateinit var authorAvatarView: ImageView
private val sharedActivityViewModel: RoomWidgetViewModel by activityViewModel()
var onFinish: ((Boolean) -> Unit)? = null
override fun invalidate() = withState(viewModel) { state ->
......@@ -63,9 +62,13 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() {
VectorUtils.loadUserAvatar(requireContext(), viewModel.session, authorAvatarView,
state.authorAvatarUrl, state.authorId, state.authorName)
val domain = state.widgetDomain ?: ""
val infoBuilder = SpannableStringBuilder()
.append(getString(R.string.room_widget_permission_shared_info_title, "'${state.widgetDomain
?: ""}'"))
.append(getString(
R.string.room_widget_permission_webview_shared_info_title
.takeIf { state.isWebviewWidget }
?: R.string.room_widget_permission_shared_info_title,
"'$domain'"))
infoBuilder.append("\n")
state.permissionsList?.forEach {
......@@ -94,19 +97,21 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() {
viewModel.blockWidget()
//optimistic dismiss
dismiss()
sharedActivityViewModel.doFinish()
onFinish?.invoke(false)
}
@OnClick(R.id.bottom_sheet_widget_permission_continue_button)
fun doAccept() {
viewModel.allowWidget()
onFinish?.invoke(true)
//optimistic dismiss
dismiss()
}
override fun onCancel(dialog: DialogInterface?) {
super.onCancel(dialog)
sharedActivityViewModel.doFinish()
onFinish?.invoke(false)
}
@Parcelize
......
......@@ -21,17 +21,19 @@ import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import im.vector.Matrix
import im.vector.R
import im.vector.activity.JitsiCallActivity
import im.vector.util.extractDomain
import im.vector.widgets.Widget
import im.vector.widgets.WidgetsManager
import org.matrix.androidsdk.MXSession
import org.matrix.androidsdk.core.Log
import org.matrix.androidsdk.core.callback.ApiCallback
import org.matrix.androidsdk.core.model.MatrixError
import org.matrix.androidsdk.core.callback.SimpleApiCallback
import java.net.URL
data class RoomWidgetPermissionViewState(
val authorId: String = "",
val authorAvatarUrl: String? = null,
val authorName: String? = null,
val isWebviewWidget: Boolean = true,
val widgetDomain: String? = null,
//List of @StringRes
val permissionsList: List<Int>? = null
......@@ -40,49 +42,48 @@ data class RoomWidgetPermissionViewState(
class RoomWidgetPermissionViewModel(val session: MXSession, val widget: Widget, initialState: RoomWidgetPermissionViewState)
: BaseMvRxViewModel<RoomWidgetPermissionViewState>(initialState, false) {
fun allowWidget(onFinished: (() -> Unit)? = null) {
session.integrationManager.setWidgetAllowed(widget.widgetEvent?.eventId
?: "", true, object : ApiCallback<Void?> {
fun allowWidget(onFinished: (() -> Unit)? = null) = withState { state ->
override fun onSuccess(info: Void?) {
onFinished?.invoke()
}
if (state.isWebviewWidget) {
session.integrationManager.setWidgetAllowed(widget.widgetEvent?.eventId
?: "", true, object : SimpleApiCallback<Void?>() {
override fun onUnexpectedError(e: Exception) {
Log.e(LOG_TAG, e.message)
}
override fun onSuccess(info: Void?) {
onFinished?.invoke()
}
override fun onNetworkError(e: Exception) {
Log.e(LOG_TAG, e.message)
}
})
} else {
session.integrationManager.seVideoConfDomainAllowed(state.widgetDomain
?: "", true, object : SimpleApiCallback<Void?>() {
override fun onMatrixError(e: MatrixError) {
Log.e(LOG_TAG, e.message)
}
override fun onSuccess(info: Void?) {
onFinished?.invoke()
}
})
})
}
}
fun blockWidget(onFinished: (() -> Unit)? = null) {
session.integrationManager.setWidgetAllowed(widget.widgetEvent?.eventId
?: "", false, object : ApiCallback<Void?> {
override fun onSuccess(info: Void?) {
onFinished?.invoke()
}
fun blockWidget(onFinished: (() -> Unit)? = null) = withState { state ->
if (state.isWebviewWidget) {
session.integrationManager.setWidgetAllowed(widget.widgetEvent?.eventId
?: "", false, object : SimpleApiCallback<Void?>() {
override fun onSuccess(info: Void?) {
onFinished?.invoke()
}
override fun onUnexpectedError(e: Exception) {
Log.e(LOG_TAG, e.message)
}
})
} else {
session.integrationManager.seVideoConfDomainAllowed(state.widgetDomain
?: "", false, object : SimpleApiCallback<Void?>() {
override fun onNetworkError(e: Exception) {
Log.e(LOG_TAG, e.message)
}
override fun onMatrixError(e: MatrixError) {
Log.e(LOG_TAG, e.message)
}
override fun onSuccess(info: Void?) {
onFinished?.invoke()
}
})
})
}
}
companion object : MvRxViewModelFactory<RoomWidgetPermissionViewModel, RoomWidgetPermissionViewState> {
......@@ -110,23 +111,41 @@ class RoomWidgetPermissionViewModel(val session: MXSession, val widget: Widget,
domain = null
}
//TODO check from widget urls the perms that should be shown?
//For now put all
val infoShared = listOf<Int>(
R.string.room_widget_permission_display_name,
R.string.room_widget_permission_avatar_url,
R.string.room_widget_permission_user_id,
R.string.room_widget_permission_theme,
R.string.room_widget_permission_widget_id,
R.string.room_widget_permission_room_id
)
return RoomWidgetPermissionViewState(
authorName = creator?.displayname,
authorId = widget.widgetEvent.sender,
authorAvatarUrl = creator?.getAvatarUrl(),
widgetDomain = domain,
permissionsList = infoShared
)
if (WidgetsManager.isJitsiWidget(widget)) {
val infoShared = listOf<Int>(
R.string.room_widget_permission_display_name,
R.string.room_widget_permission_avatar_url
)
return RoomWidgetPermissionViewState(
isWebviewWidget = false,
authorName = creator?.displayname,
authorId = widget.widgetEvent.sender,
authorAvatarUrl = creator?.getAvatarUrl(),
widgetDomain = extractDomain(JitsiCallActivity.JITSI_SERVER_URL),
permissionsList = infoShared
)
} else {
//TODO check from widget urls the perms that should be shown?
//For now put all
val infoShared = listOf<Int>(
R.string.room_widget_permission_display_name,
R.string.room_widget_permission_avatar_url,
R.string.room_widget_permission_user_id,
R.string.room_widget_permission_theme,
R.string.room_widget_permission_widget_id,
R.string.room_widget_permission_room_id
)
return RoomWidgetPermissionViewState(
authorName = creator?.displayname,
authorId = widget.widgetEvent.sender,
authorAvatarUrl = creator?.getAvatarUrl(),
widgetDomain = domain,
permissionsList = infoShared
)
}
}
}
}
\ No newline at end of file
......@@ -16,6 +16,9 @@
package im.vector.util
import java.net.MalformedURLException
import java.net.URL
/**
* Schemes
*/
......@@ -41,4 +44,12 @@ fun removeUrlScheme(aUrl: String?): String? {
}
return urlRetValue
}
fun extractDomain(aUrl: String?): String? {
try {
return aUrl?.let { URL(it).host }
} catch (e : MalformedURLException) {
return null
}
}
\ No newline at end of file
......@@ -99,6 +99,22 @@ public class WidgetsManager {
return getActiveWidgets(session, room, null, null);
}
public static Boolean isJitsiWidget(Widget widget) {
Event widgetEvent = widget.getWidgetEvent();
if (widgetEvent == null) return false;
try {
JsonObject jsonObject = widgetEvent.getContentAsJsonObject();
if (jsonObject != null && jsonObject.has("type")) {
String widgetType = jsonObject.get("type").getAsString();
return WIDGET_TYPE_JITSI.equals(widgetType);
}
} catch (Exception e) {
Log.e(LOG_TAG, "## getWidgets() failed : " + e.getMessage(), e);
}
return false;
}
/**
* List all active widgets in a room.
*
......
......@@ -1118,7 +1118,8 @@
<string name="room_widget_activity_title">Widget</string>
<string name="room_widget_permission_title">Load Widget</string>
<string name="room_widget_permission_added_by">This widget was added by:</string>
<string name="room_widget_permission_shared_info_title">Using it may set cookies and share data with %s:</string>
<string name="room_widget_permission_webview_shared_info_title">Using it may set cookies and share data with %s:</string>
<string name="room_widget_permission_shared_info_title">Using it may share data with %s:</string>
<string name="room_widget_failed_to_load">Failed to load widget.\n%s</string>
<string name="room_widget_reload">Reload widget</string>
<string name="room_widget_open_in_browser">Open in browser</string>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment