Unverified Commit 3b9839bd authored by Diego Mello's avatar Diego Mello Committed by GitHub
Browse files

Merge 4.13.1 into master (#2773)



* [NEW] Omnichannel Status Toggle (#2217)
Co-authored-by: default avatarDiego Mello <diegolmello@gmail.com>

* [FIX] Typing when UI_Use_Real_Name is enabled (#2216)
Co-authored-by: default avatarDiego Mello <diegolmello@gmail.com>

* [REGRESSION] Logout failing after #2217 (#2222)

* [CHORE] Add wrapper to make Meteor methods calls over REST (#2104)

* [WIP] Use rest instead methodCall

* [WIP] Some method calls using wrapper

* [WIP] Wrap all necessary methodCalls

* fix
Co-authored-by: default avatarDiego Mello <diegolmello@gmail.com>

* [IMPROVEMENT] Mark thread as read on open (#2225)

* [IMPROVEMENT] Mark a thread as read

* Use methodCallWrapper

* Check server version
Co-authored-by: default avatarDiego Mello <diegolmello@gmail.com>

* [FIX] Read receipt icon on action sheet (#2237)

* [FIX] Handle TypeErrors on navigationRef and draftMessage due to null properties (#2232)
Co-authored-by: default avatarDiego Mello <diegolmello@gmail.com>

* [FIX] Android crashing when restoring from backgroun...
parent 12bb23a9
......@@ -144,7 +144,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer
versionName "4.13.0"
versionName "4.13.1"
vectorDrawables.useSupportLibrary = true
if (!isFoss) {
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
......
......@@ -15,9 +15,6 @@ export const merge = (subscription, room) => {
if (room) {
if (room._updatedAt) {
subscription.lastMessage = normalizeMessage(room.lastMessage);
const updatedAt = room?._updatedAt ? new Date(room._updatedAt) : null;
const lastMessageTs = subscription?.lastMessage?.ts ? new Date(subscription.lastMessage.ts) : null;
subscription.roomUpdatedAt = Math.max(updatedAt, lastMessageTs);
subscription.description = room.description;
subscription.topic = room.topic;
subscription.announcement = room.announcement;
......@@ -28,6 +25,9 @@ export const merge = (subscription, room) => {
subscription.usernames = room.usernames;
subscription.uids = room.uids;
}
// https://github.com/RocketChat/Rocket.Chat/blob/develop/app/ui-sidenav/client/roomList.js#L180
const lastRoomUpdate = room.lm || subscription.ts || subscription._updatedAt;
subscription.roomUpdatedAt = subscription.lr ? Math.max(new Date(subscription.lr), new Date(lastRoomUpdate)) : lastRoomUpdate;
subscription.ro = room.ro;
subscription.broadcast = room.broadcast;
subscription.encrypted = room.encrypted;
......
......@@ -15,7 +15,6 @@ import {
} from '../actions/app';
import { localAuthenticate } from '../utils/localAuthentication';
import { goRoom } from '../utils/goRoom';
import callJitsi from '../lib/methods/callJitsi';
const roomTypes = {
channel: 'c', direct: 'd', group: 'p', channels: 'l'
......@@ -54,7 +53,7 @@ const navigate = function* navigate({ params }) {
yield goRoom({ item, isMasterDetail });
if (params.isCall) {
callJitsi(item.rid);
RocketChat.callJitsi(item.rid);
}
}
} else {
......
class FileUpload {
_xhr = new XMLHttpRequest();
class Upload {
constructor() {
this.xhr = new XMLHttpRequest();
this.formData = new FormData();
}
then = (callback) => {
this.xhr.onload = () => callback({ respInfo: this.xhr });
this.xhr.send(this.formData);
}
catch = (callback) => {
this.xhr.onerror = callback;
}
_formData = new FormData();
uploadProgress = (callback) => {
this.xhr.upload.onprogress = ({ total, loaded }) => callback(loaded, total);
}
cancel = () => {
this.xhr.abort();
return Promise.resolve();
}
}
class FileUpload {
fetch = (method, url, headers, data) => {
this._xhr.open(method, url);
const upload = new Upload();
upload.xhr.open(method, url);
Object.keys(headers).forEach((key) => {
this._xhr.setRequestHeader(key, headers[key]);
upload.xhr.setRequestHeader(key, headers[key]);
});
data.forEach((item) => {
if (item.uri) {
this._formData.append(item.name, {
upload.formData.append(item.name, {
uri: item.uri,
type: item.type,
name: item.filename
});
} else {
this._formData.append(item.name, item.data);
upload.formData.append(item.name, item.data);
}
});
return this;
}
then = (callback) => {
this._xhr.onload = () => callback({ respInfo: this._xhr });
this._xhr.send(this._formData);
}
catch = (callback) => {
this._xhr.onerror = callback;
}
uploadProgress = (callback) => {
this._xhr.upload.onprogress = ({ total, loaded }) => callback(loaded, total);
}
cancel = () => {
this._xhr.abort();
return Promise.resolve();
return upload;
}
}
......
......@@ -119,7 +119,8 @@ class AttachmentView extends React.Component {
this.setState({ loading: true });
try {
const extension = image_url ? `.${ mime.extension(image_type) || 'jpg' }` : `.${ mime.extension(video_type) || 'mp4' }`;
const path = `${ RNFetchBlob.fs.dirs.DocumentDir + SHA256(url) + extension }`;
const documentDir = `${ RNFetchBlob.fs.dirs.DocumentDir }/`;
const path = `${ documentDir + SHA256(url) + extension }`;
const file = await RNFetchBlob.config({ path }).fetch('GET', mediaAttachment).then(res => res.path());
await CameraRoll.save(file, { album: 'Rocket.Chat' });
EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') });
......
......@@ -10,11 +10,14 @@ def all_pods
use_flipper!
end
target 'RocketChatRN' do
abstract_target 'defaults' do
# force use our own JitsiMeetSDK
pod 'JitsiMeetSDK', :git => 'https://github.com/RocketChat/jitsi-meet-ios-sdk-releases.git'
all_pods
target 'RocketChatRN' # Experimental app
target 'Rocket.Chat' # Official app
end
target 'ShareRocketChatRN' do
......
This diff is collapsed.
# Flipper [![Build Status](https://travis-ci.org/facebook/flipper.svg?branch=master)](https://travis-ci.org/facebook/flipper) [![Android Maven Badge](https://img.shields.io/maven-metadata/v/https/jcenter.bintray.com/com/facebook/flipper/flipper/maven-metadata.xml.svg?color=green&label=android)](https://bintray.com/facebook/maven/com.facebook.flipper%3Aflipper) [![iOS](https://img.shields.io/cocoapods/v/FlipperKit.svg?label=iOS&color=blue)](https://cocoapods.org/pods/Flipper) [![Greenkeeper badge](https://badges.greenkeeper.io/facebook/flipper.svg)](https://greenkeeper.io/)
Flipper (formerly Sonar) is a platform for debugging mobile apps on iOS and Android. Visualize, inspect, and control your apps from a simple desktop interface. Use Flipper as is or extend it using the plugin API.
![Flipper](/docs/assets/layout.png)
<p align="center">
<img src="https://fbflipper.com/img/icon.png" alt="logo" width="20%"/>
</p>
<h1 align="center">
Flipper
</h1>
<p align="center">
<a href="https://travis-ci.org/facebook/flipper">
<img src="https://travis-ci.org/facebook/flipper.svg?branch=master" alt="Build Status" />
</a>
<a href="https://bintray.com/facebook/maven/com.facebook.flipper%3Aflipper">
<img src="https://img.shields.io/maven-metadata/v/https/jcenter.bintray.com/com/facebook/flipper/flipper/maven-metadata.xml.svg?color=green&label=android" alt="Android Maven Badge" />
</a>
<a href="https://cocoapods.org/pods/Flipper">
<img src="https://img.shields.io/cocoapods/v/FlipperKit.svg?label=iOS&color=blue" alt="iOS" />
</a>
</p>
<p align="center">
Flipper (formerly Sonar) is a platform for debugging mobile apps on iOS and Android. Visualize, inspect, and control your apps from a simple desktop interface. Use Flipper as is or extend it using the plugin API.
</p>
![Flipper](/website/static/img/layout.png)
## Table of Contents
......@@ -32,7 +50,7 @@ Flipper is built as a platform. In addition to using the tools already included,
## Contributing to Flipper
Both Flipper's desktop app and native mobile SDKs are open-source and MIT licensed. This enables you to see and understand how we are building plugins, and of course, join the community and help improve Flipper. We are excited to see what you will build on this platform.
Both Flipper's desktop app and native mobile SDKs are open-source and MIT licensed. This enables you to see and understand how we are building plugins, and of course, join the community and help to improve Flipper. We are excited to see what you will build on this platform.
# In this repo
......
......@@ -8,12 +8,10 @@
#include "ConnectionContextStore.h"
#include <folly/json.h>
#include <folly/portability/SysStat.h>
#include <stdio.h>
#include <fstream>
#include <iostream>
#include "CertificateUtils.h"
#include "Log.h"
using namespace facebook::flipper;
static constexpr auto CSR_FILE_NAME = "app.csr";
......
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
enum FlipperCertificateExchangeMedium { FS_ACCESS = 1, WWW = 2 };
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <functional>
#include <string>
#include "FlipperCertificateExchangeMedium.h"
#include "FlipperState.h"
#include "FlipperStep.h"
namespace facebook {
namespace flipper {
/**
* Represents a FlipperCertificateProvider which is responsible for obtaining
* Flipper TLS certificates.
*/
class FlipperCertificateProvider {
public:
virtual ~FlipperCertificateProvider() {}
/**
* Gets certificates downloaded at a path, which is passed as an argument.
*/
virtual void getCertificates(
const std::string& path,
const std::string& deviceID) = 0;
/**
* Sets certificate exchange medium
*/
virtual void setCertificateExchangeMedium(
const FlipperCertificateExchangeMedium medium) = 0;
/**
* Gets certificate exchange medium
*/
virtual FlipperCertificateExchangeMedium getCertificateExchangeMedium() = 0;
/**
* This lets the Client know if it should reset the connection folder when
* `stop` is called.
*/
virtual bool shouldResetCertificateFolder() = 0;
/**
* Sets the FlipperState, so that Cert Provider can send debuggin information
* to troubleshoot screen.
*/
virtual void setFlipperState(std::shared_ptr<FlipperState> state) = 0;
};
} // namespace flipper
} // namespace facebook
......@@ -73,6 +73,17 @@ void FlipperClient::addPlugin(std::shared_ptr<FlipperPlugin> plugin) {
});
}
void FlipperClient::setCertificateProvider(
const std::shared_ptr<FlipperCertificateProvider> provider) {
socket_->setCertificateProvider(provider);
log("cpp setCertificateProvider called");
}
std::shared_ptr<FlipperCertificateProvider>
FlipperClient::getCertificateProvider() {
return socket_->getCertificateProvider();
}
void FlipperClient::removePlugin(std::shared_ptr<FlipperPlugin> plugin) {
performAndReportError([this, plugin]() {
log("FlipperClient::removePlugin " + plugin->identifier());
......
......@@ -10,6 +10,7 @@
#include <map>
#include <mutex>
#include <vector>
#include "FlipperCertificateProvider.h"
#include "FlipperConnectionImpl.h"
#include "FlipperConnectionManager.h"
#include "FlipperInitConfig.h"
......@@ -85,6 +86,10 @@ class FlipperClient : public FlipperConnectionManager::Callbacks {
void setStateListener(
std::shared_ptr<FlipperStateUpdateListener> stateListener);
void setCertificateProvider(
const std::shared_ptr<FlipperCertificateProvider> provider);
std::shared_ptr<FlipperCertificateProvider> getCertificateProvider();
std::shared_ptr<FlipperPlugin> getPlugin(const std::string& identifier);
std::string getState();
......
......@@ -8,6 +8,7 @@
#pragma once
#include <folly/json.h>
#include "FlipperCertificateProvider.h"
#include "FlipperResponder.h"
namespace facebook {
......@@ -30,6 +31,18 @@ class FlipperConnectionManager {
*/
virtual void stop() = 0;
/**
Sets the Auth token to be used for hitting an Intern end point
*/
virtual void setCertificateProvider(
const std::shared_ptr<FlipperCertificateProvider> provider) = 0;
/**
Gets the certificate provider
*/
virtual std::shared_ptr<FlipperCertificateProvider>
getCertificateProvider() = 0;
/**
True if there's an open connection.
This method may block if the connection is busy.
......
......@@ -90,6 +90,16 @@ FlipperConnectionManagerImpl::~FlipperConnectionManagerImpl() {
stop();
}
void FlipperConnectionManagerImpl::setCertificateProvider(
const std::shared_ptr<FlipperCertificateProvider> provider) {
certProvider_ = provider;
};
std::shared_ptr<FlipperCertificateProvider>
FlipperConnectionManagerImpl::getCertificateProvider() {
return certProvider_;
};
void FlipperConnectionManagerImpl::start() {
if (isStarted_) {
log("Already started");
......@@ -169,10 +179,13 @@ void FlipperConnectionManagerImpl::startSync() {
bool FlipperConnectionManagerImpl::doCertificateExchange() {
rsocket::SetupParameters parameters;
folly::SocketAddress address;
int medium = certProvider_ != nullptr
? certProvider_->getCertificateExchangeMedium()
: FlipperCertificateExchangeMedium::FS_ACCESS;
parameters.payload = rsocket::Payload(folly::toJson(folly::dynamic::object(
"os", deviceData_.os)("device", deviceData_.device)(
"app", deviceData_.app)("sdk_version", sdkVersion)));
"app", deviceData_.app)("sdk_version", sdkVersion)("medium", medium)));
address.setFromHostPort(deviceData_.host, insecurePort);
auto connectingInsecurely = flipperState_->start("Connect insecurely");
......@@ -198,6 +211,7 @@ bool FlipperConnectionManagerImpl::doCertificateExchange() {
.get();
if (newClient.get() == nullptr) {
connectingInsecurely->fail("Failed to connect");
return false;
}
......@@ -221,12 +235,15 @@ bool FlipperConnectionManagerImpl::connectSecurely() {
if (deviceId.compare("unknown")) {
loadingDeviceId->complete();
}
int medium = certProvider_ != nullptr
? certProvider_->getCertificateExchangeMedium()
: FlipperCertificateExchangeMedium::FS_ACCESS;
parameters.payload = rsocket::Payload(folly::toJson(folly::dynamic::object(
"csr", contextStore_->getCertificateSigningRequest().c_str())(
"csr_path", contextStore_->getCertificateDirectoryPath().c_str())(
"os", deviceData_.os)("device", deviceData_.device)(
"device_id", deviceId)("app", deviceData_.app)(
"device_id", deviceId)("app", deviceData_.app)("medium", medium)(
"sdk_version", sdkVersion)));
address.setFromHostPort(deviceData_.host, securePort);
......@@ -257,6 +274,7 @@ bool FlipperConnectionManagerImpl::connectSecurely() {
})
.get();
if (newClient.get() == nullptr) {
connectingSecurely->fail("Failed to connect");
return false;
}
......@@ -278,6 +296,9 @@ void FlipperConnectionManagerImpl::reconnect() {
}
void FlipperConnectionManagerImpl::stop() {
if (certProvider_ && certProvider_->shouldResetCertificateFolder()) {
contextStore_->resetState();
}
if (!isStarted_) {
log("Not started");
return;
......@@ -338,10 +359,13 @@ void FlipperConnectionManagerImpl::requestSignedCertFromFlipper() {
auto generatingCSR = flipperState_->start("Generate CSR");
std::string csr = contextStore_->getCertificateSigningRequest();
generatingCSR->complete();
int medium = certProvider_ != nullptr
? certProvider_->getCertificateExchangeMedium()
: FlipperCertificateExchangeMedium::FS_ACCESS;
folly::dynamic message =
folly::dynamic::object("method", "signCertificate")("csr", csr.c_str())(
"destination", contextStore_->getCertificateDirectoryPath().c_str());
"destination", contextStore_->getCertificateDirectoryPath().c_str())(
"medium", medium);
auto gettingCert = flipperState_->start("Getting cert from desktop");
flipperEventBase_->add([this, message, gettingCert]() {
......@@ -354,8 +378,34 @@ void FlipperConnectionManagerImpl::requestSignedCertFromFlipper() {
folly::dynamic config = folly::parseJson(response);
contextStore_->storeConnectionConfig(config);
}
gettingCert->complete();
if (certProvider_) {
certProvider_->setFlipperState(flipperState_);
auto gettingCertFromProvider =
flipperState_->start("Getting cert from Cert Provider");
try {
// Certificates should be present in app's sandbox after it is
// returned. The reason we can't have a completion block here
// is because if the certs are not present after it returns
// then the flipper tries to reconnect on insecured channel
// and recreates the app.csr. By the time completion block is
// called the DeviceCA cert doesn't match app's csr and it
// throws an SSL error.
certProvider_->getCertificates(
contextStore_->getCertificateDirectoryPath(),
contextStore_->getDeviceId());
gettingCertFromProvider->complete();
} catch (std::exception& e) {
gettingCertFromProvider->fail(e.what());
gettingCert->fail(e.what());
} catch (...) {
gettingCertFromProvider->fail("Exception from certProvider");
gettingCert->fail("Exception from certProvider");
}
}
log("Certificate exchange complete.");
gettingCert->complete();
// Disconnect after message sending is complete.
// This will trigger a reconnect which should use the secure
// channel.
......
......@@ -50,10 +50,14 @@ class FlipperConnectionManagerImpl : public FlipperConnectionManager {
std::unique_ptr<FlipperResponder> responder) override;
void reconnect();
void setCertificateProvider(
const std::shared_ptr<FlipperCertificateProvider> provider) override;
std::shared_ptr<FlipperCertificateProvider> getCertificateProvider() override;
private:
bool isOpen_ = false;
bool isStarted_ = false;
std::shared_ptr<FlipperCertificateProvider> certProvider_ = nullptr;
Callbacks* callbacks_;
DeviceData deviceData_;
std::shared_ptr<FlipperState> flipperState_;
......
# Flipper [![Build Status](https://travis-ci.org/facebook/flipper.svg?branch=master)](https://travis-ci.org/facebook/flipper) [![Android Maven Badge](https://img.shields.io/maven-metadata/v/https/jcenter.bintray.com/com/facebook/flipper/flipper/maven-metadata.xml.svg?color=green&label=android)](https://bintray.com/facebook/maven/com.facebook.flipper%3Aflipper) [![iOS](https://img.shields.io/cocoapods/v/FlipperKit.svg?label=iOS&color=blue)](https://cocoapods.org/pods/Flipper) [![Greenkeeper badge](https://badges.greenkeeper.io/facebook/flipper.svg)](https://greenkeeper.io/)
Flipper (formerly Sonar) is a platform for debugging mobile apps on iOS and Android. Visualize, inspect, and control your apps from a simple desktop interface. Use Flipper as is or extend it using the plugin API.
![Flipper](/docs/assets/layout.png)
<p align="center">
<img src="https://fbflipper.com/img/icon.png" alt="logo" width="20%"/>
</p>
<h1 align="center">
Flipper
</h1>
<p align="center">
<a href="https://travis-ci.org/facebook/flipper">
<img src="https://travis-ci.org/facebook/flipper.svg?branch=master" alt="Build Status" />
</a>
<a href="https://bintray.com/facebook/maven/com.facebook.flipper%3Aflipper">
<img src="https://img.shields.io/maven-metadata/v/https/jcenter.bintray.com/com/facebook/flipper/flipper/maven-metadata.xml.svg?color=green&label=android" alt="Android Maven Badge" />
</a>
<a href="https://cocoapods.org/pods/Flipper">
<img src="https://img.shields.io/cocoapods/v/FlipperKit.svg?label=iOS&color=blue" alt="iOS" />
</a>
</p>
<p align="center">
Flipper (formerly Sonar) is a platform for debugging mobile apps on iOS and Android. Visualize, inspect, and control your apps from a simple desktop interface. Use Flipper as is or extend it using the plugin API.
</p>
![Flipper](/website/static/img/layout.png)
## Table of Contents
......@@ -32,7 +50,7 @@ Flipper is built as a platform. In addition to using the tools already included,
## Contributing to Flipper
Both Flipper's desktop app and native mobile SDKs are open-source and MIT licensed. This enables you to see and understand how we are building plugins, and of course, join the community and help improve Flipper. We are excited to see what you will build on this platform.
Both Flipper's desktop app and native mobile SDKs are open-source and MIT licensed. This enables you to see and understand how we are building plugins, and of course, join the community and help to improve Flipper. We are excited to see what you will build on this platform.
# In this repo
......
......@@ -8,6 +8,7 @@
#ifdef FB_SONARKIT_ENABLED
#import <Foundation/Foundation.h>
#import "FlipperKitCertificateProvider.h"
#import "FlipperPlugin.h"
#import "FlipperStateUpdateListener.h"
......@@ -64,6 +65,16 @@ Subscribe a ViewController to state update change notifications
*/
- (void)subscribeForUpdates:(id<FlipperStateUpdateListener>)controller;
/**
Sets the certificate provider responsible for obtaining certificates
*/
- (void)setCertificateProvider:(id<FlipperKitCertificateProvider>)provider;
/**
Get the certificate provider of Flipper Client
*/
- (id<FlipperKitCertificateProvider>)getCertificateProvider;
// initializers are disabled. You must use `+[FlipperClient sharedClient]`
// instance.
- (instancetype)init NS_UNAVAILABLE;
......
......@@ -8,15 +8,17 @@
#if FB_SONARKIT_ENABLED
#import "FlipperClient.h"
#import <Flipper/FlipperCertificateProvider.h>
#import <Flipper/FlipperClient.h>
#import <UIKit/UIKit.h>
#include <folly/io/async/EventBase.h>
#include <folly/io/async/ScopedEventBaseThread.h>
#include <memory>
#import "FlipperClient+Testing.h"
#import "FlipperCppWrapperPlugin.h"
#import "FlipperKitCertificateProvider.h"
#import "SKEnvironmentVariables.h"
#include "SKStateUpdateCPPWrapper.h"
#if !TARGET_OS_SIMULATOR
#import <FKPortForwarding/FKPortForwardingServer.h>
#endif
......@@ -27,6 +29,7 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
facebook::flipper::FlipperClient* _cppClient;
folly::ScopedEventBaseThread sonarThread;
folly::ScopedEventBaseThread connectionThread;
id<FlipperKitCertificateProvider> _certProvider;
#if !TARGET_OS_SIMULATOR
FKPortForwardingServer* _secureServer;
FKPortForwardingServer* _insecureServer;
......@@ -46,7 +49,6 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
});
return sharedClient;
}
- (instancetype)init {
if (self = [super init]) {
UIDevice* device = [UIDevice currentDevice];
......@@ -57,9 +59,7 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
NSString* appId = [bundle bundleIdentifier];
NSString* privateAppDirectory = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory, NSUserDomainMask, YES)[0];
NSFileManager* manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:privateAppDirectory isDirectory:NULL] == NO &&
![manager createDirectoryAtPath:privateAppDirectory
withIntermediateDirectories:YES
......@@ -99,6 +99,19 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
return self;
}