Stream Chat returns all channels by default - getstream-io

I'm using the React Stream Chat components and by default I'm getting all channels, even the ones the set user isn't a member of. This is how I set the user:
await client.setUser(
{
id: user.id.toString(),
name: user.name,
},
user.streamToken,
);
And this what the chat component looks like.
<Chat client={chatClient}>
<ChannelList />
<Channel>
<Window>
<MessageList />
<MessageInput />
</Window>
<Thread />
</Channel>
</Chat>
All Channels have been created with just two members and the documentation says:
You only need to specify the members if you want to limit access of this chat to these members and subscribe them to future updates
When logging the channels I can verify that I'm getting channels I'm not a member of.
Is that the intended behavior or am I missing something?
There's a workaround by passing a filter to the ChannelList:
const filters = { members: { $in: [currentUser.id.toString()] } };

You probably have your permission checks turned off. You can enable them on the Stream Dashboard.
It's under "Disable Permissions Checks". Toggling this should activate the permission checks and show all the Channels that only you are a member of.
Still you'd want to keep the filter in your app.

Related

Switching between stripe checkouts for platform account and connected account (to save card on platform account)

I am using stripe connect.
I am using strong customer authentication and payment methods
I want customers to be able to save their card on my platform account so that I can then charge their cards on all connected accounts.
For example, if a user ticks a checkbox stating 'save my card for future use', I want to save their card on my platform account.
However, if this checkbox is not ticked, I want to charge the customer of the connected account instead.
I am having difficulties switching between my platform account and the connected account on my front end.
I have saved to instances of Stripes checkout to variables:
let checkoutFormConnected = (
this.state.userEvent.organiser.stripeAccountID !== "" && (
<StripeProvider
apiKey={process.env.REACT_APP_API_STRIPE_PUBLISH}
stripeAccount={this.state.userEvent.organiser.stripeAccountID}
>
<Elements>
<CheckoutForm/>
</Elements>
</StripeProvider>
)
);
let checkoutFormNotConnected = (
this.state.userEvent.organiser.stripeAccountID !== "" && (
<StripeProvider
apiKey={process.env.REACT_APP_API_STRIPE_PUBLISH}
>
<Elements>
<CheckoutForm />
</Elements>
</StripeProvider>
)
);
and I am displaying them depending on whether the checkbox for saving the card is ticked:
{this.state.checkBoxes.saveCard ? checkoutFormNotConnected : checkoutFormConnected}
However, it appears that whichever checkoutForm is first rendered remains even after I switch between the two checkoutForm variables.
I have tested to ensure that I am switching between these two options by displaying prop values on screen.
When the connected account checkout appears on screen first, and then switches to the platform account checkout, when I try to save the card on the platform account I get the error: "No such setupintent: 'seti_1Hw8LXCFzSpFw85fowNQm634'"
This is displaying because the backend created the setup intent on the connected account, even though I switched to the variable holding the checkoutForm for the platform account.
It appears that the checkoutForm won't re-render once it has rendered on the page.
For reference my backend code is
const customer = await stripe.customers.create();
const Intent = stripe.setupIntents.create({
customer: customer.id,
});
const UpdateCustomer = User.findByIdAndUpdate(req.body.purchaserID, {
stripeCustomerID: customer.id,
});
Promise.all([Intent, UpdateCustomer]).then((data) => {
res.send({
customerID: customer.id,
clientSecret: data[0].client_secret,
});
});
The docs only show how to save a card during payment for accounts that are not connected.
I have also coded this so that the platform account appears first on the page. Then I can save the card on the platform account and charge it in the future. I do this by cloning payment methods But when the checkoutForm changes to charge a new card (on a connected account) I get the same error about payment intents (because it is trying to set it up on the platform account)
How can I re-render the stripe checkout to switch between the platform account and the connected account?
Update: this works!:
<StripeProvider
apiKey={process.env.REACT_APP_API_STRIPE_PUBLISH}
stripeAccount={this.state.userEvent.organiser.stripeAccountID || undefined}
key={this.state.checkBoxes.saveCard || 'platform'}
>
One solution to this would be to use React's special key prop to force the checkout form to re-mount whenever the Stripe account changes. For example:
<StripeProvider
apiKey={process.env.REACT_APP_API_STRIPE_PUBLISH}
stripeAccount={this.state.userEvent.organiser.stripeAccountID || undefined}
key={this.state.userEvent.organiser.stripeAccountID || 'platform'}
>
<Elements>
<CheckoutForm/>
</Elements>
</StripeProvider>
The key prop in React is typically only used when rendering elements in an array. The idea is that you add unique keys to each element in the array to help React keep track of what elements changes and which ones don't. React encourages you to add a key prop whenever rendering a list of items, but it isn't strictly necessary unless the order of those list items change. You can read more on that here:
https://reactjs.org/docs/lists-and-keys.html#keys
https://kentcdodds.com/blog/understanding-reacts-key-prop
The reason I added a || 'platform' to the value of the key prop is to trigger a re-mount when this.state.userEvent.organiser.stripeAccountID is undefined or falsey. I'm making the assumption that this.state.userEvent.organiser.stripeAccountID will be falsey if you don't want to collect the payment method as the connected account. React doesn't treat falsey values as valid keys, so without that || 'platform' there would be no perceived change, and no re-mount.

Proactive messaging bot in Teams without mentioning the bot beforehand

I'm using the Microsoft bot-framework to create a bot and integrate it into teams.
Part of the bot's requirements include proactively messaging users once per day. From what I understand, I can only message users that has been added to the team/groupChat after the bot, or that have messaged the bot directly.
My question is - can I somehow bypass this limitation?
A friend of my referred me to a new feature of graphAPI, as part of the new beta version - https://learn.microsoft.com/en-us/graph/api/user-add-teamsappinstallation?view=graph-rest-beta&tabs=http.
To me it doesn't seem like it could be related to the solution since I'm not getting any data back in the response, so if I have no conversationReference object I still can't message the user.
At the moment my solution is to simply broadcast a message in the channel when it's added, asking users to "register" with it by messaging it. Anyone has any other suggestion?
The easiest way is to:
Install the bot for the team
Query the Team Roster -- The link in Step 3 has an alternative way to do this towards the bottom
Create a conversation with the user and send a proactive message
There's a lot of code in those links and it's better to just visit them than to copy/paste it here.
The end of Step 3 also mentions trustServiceUrl, which you may find handy if you run into permissions/auth issues when trying to send a proactive message.
Edit for Node:
Install Necessary Packages
npm i -S npm install botbuilder-teams#4.0.0-beta1 botframework-connector
Note: The #<version> is important!
Prepare the Adapter
In index.js
const teams = require('botbuilder-teams');
adapter.use(new teams.TeamsMiddleware());
Get the Roster
// Get Team Roster
const credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
const connector = new ConnectorClient(credentials, { baseUri: context.activity.serviceUrl });
const roster = await connector.conversations.getConversationMembers(context.activity.conversation.id);
Send the Proactive Message
const { TeamsContext } = require('botbuilder-teams');
// Send Proactive Message
const teamsCtx = TeamsContext.from(context);
const parameters = {
members: [
roster[0] // Replace with appropriate user
],
channelData: {
tenant: {
id: teamsCtx.tenant.id
}
}
};
const conversationResource = await connector.conversations.createConversation(parameters);
const message = MessageFactory.text('This is a proactive message');
await connector.conversations.sendToConversation(conversationResource.id, message);
Trust the ServiceUrl, as Necessary
Read about it. You'd want this before the message is sent.
MicrosoftAppCredentials.trustServiceUrl(context.activity.serviceUrl);
EDIT: The Graph API you've referenced is only necessary if you wish to proactively message a user who is not in a channel/groupChat where the bot is installed. If you need to proactively message only people who are in context where the bot is installed already, the answer from mdrichardson is the easiest possible method.
We've identified a couple of issues with the Graph API beta endpoint you referenced that should be fixed in the near term. In the meantime workarounds are as follows:
Calling:
POST https://graph.microsoft.com/beta/me/teamwork/installedApps/
{"teamsapp#odata.bind":"https://graph.microsoft.com/beta/appcatalogs/teamsapps/APP-GUID"}
Will install an app in the personal scope of a user.
Known issue: Currently, if the app contains a bot, then installation will not lead to creation of thread between the bot and the user. However to ensure that any missing chat threads, get created, call:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Calling:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Gets the chat between a user and an app containing a bot.
Known issue: Calling this API will lead to sending a conversation update event to the bot even though there were no updates to the conversation. Your bot will essentially get two install events and you'll need to make sure you don't send the welcome message twice.
We'll also be adding more detailed documentation for the proactive messaging flow using these Graph APIs

Permission for all users to post to a specific feed

I have been attempting to implement stream via react native and seem to be struggling with what looks like a permissions issue in relation to all users being unable to post to another 'entities' feed. My use case is essentially several 'topic' pages, where all users of my app can post to and comment etc. The topic page will also have an owner who can manage the page if needs be, so they too are essentially a 'user.
I've read elsewhere that global write permissions are not enabled by default so may need a member of the stream team to look at this for me if possible.
Here is the code I'm trying to use on the client side:
let user = client.feed('user', "bob");
let activity = {
actor: "bob",
verb: 'post',
object: "Hello world",
foreign_id: 'post:1',
to: ['user:topic-page-1'],
};
user
.addActivity(activity)
.then(data => {
console.log('success');
})
.catch(reason => {
alert(reason);
});
Another small issue I can't seem to get to the bottom of, is even when posting to the same user's timeline, the post username is always displaying as "Unknown" no matter what data I attach. What am I getting wrong here please?
For the actor field to be treated as a user entity, you should use a reference, something like client.currentUser or client.user('bob'). This should fix your post username issue.

Send parameters to Cortana Skill

I created a chatbot which Cortana is using as a skill, it works great, however, I'm currently reading some parameters from a blob storage file and I'd like to make it more dynamic; is there a way to send parameters upon initialization of the skill coming from Cortana? I read here:
Get the user's profile and contextual information
That Cortana can read the UserInfo such as name, email, localization, etc, but I haven't seen any way to enter custom values that I can read once the message is received on init.
I would appreciate your help, thanks!
Don't forget that Cortana is conversational (RESTful, and for the most part stateless). Ask yourself what configuration is part of the dialog, versus what is part of service. If there is configuration that is sent from the user, then it makes sense to store it on the session using one of the three contexts described: user data, conversation data, or private conversation data. This is all botframework: manage state data.
There are a couple ways you can discern if Cortana is configured or not. If you have not stored the properties on userData, assume you are not configured and change your dialog flow. If you want to check at the time you are invoked, you can always do something like this if( session.message.entities[0].name === 'Microsoft.Launch' ) { ... }
In one of my skills, I just do this... if(! session.userData.bookName ) { session.beginDialog('openBook'); return; } where openBook sets the name.
If this is service related, then you can move your configuration where you like. Keeping it in Azure storage may still require a service restart to use changes (unless you continuously poll.) Conversely, you can put the configuration data in system properties (environment variables), either in your web.config or on the container. For example,
<configuration>
<appSettings>
<!-- update these with your BotId, Microsoft App Id and your Microsoft App Password-->
<add key="BotId" value="YourBotId" />
<add key="MicrosoftAppId" value="" />
<add key="MicrosoftAppPassword" value="" /> ...
You can set IIS to watch for changed in the config file to auto-restart.
Hope this helps.

Meteor allowing me to subscribe from anywhere, security flaw

So I have made a meteor app and I have the autopublish and insecure packages removed, now in order to receive data from my collections I have to subscribe to them in the client. I also have a python program that communicates with my meteor server over ddp using the python-meteor package, in it I simply subscribe to my collections and have complete access to all my data, I can also make Meteor.calls to call functions on the server. This is nice but I can't help but feel like this is a major security hole, anyone can write a client and subscribe to my collections and grab all my data on a whim, if they guess the collection names right.
Is there a way to only let certain clients subscribe to collections and perform server calls?
Yes, you should add security checks to all publishers and methods.
Here's an example publisher that ensures the user is logged in and is a member of the group before receiving any posts related to the group:
Meteor.publish('postsForGroup', function(groupId) {
check(groupId, String);
// make sure the user is a member of the group
var group = Groups.findOne(groupId);
if (!_.contains(group.members, this.userId))
throw new Meteor.Error(403, 'You must be a member of the group!');
return Posts.find({groupId: groupId});
});
Here's an example method that ensures the user is logged in and an admin of the group before being allowed to change the group's name:
Meteor.methods({
'groups.update.name': function(groupId, name) {
check(groupId, String);
check(name, String);
// make sure the user is an admin of the group
var group = Groups.findOne(groupId);
if (!_.contains(group.admins, this.userId))
throw new Meteor.Error(403, 'You must be an admin of the group!');
// make sure the name isn't empty
if (!name.length)
throw new Meteor.Error(403, 'Name can not be empty!');
return Groups.update(groupId, {$set: {name: name}});
}
});
One detail to watch out for: If you are using iron router, be careful not to cause any errors in your publishers. Doing so, will cause waitOn to never return. If you think that throwing an error is possible under normal operation, then I'd recommend return this.ready() instead of throw new Meteor.Error in your publisher.

Resources