PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync duplicate channel - c#

We use Azure Notifications Hub to manage notifications registrations. Every time user launches application, we call PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync and then RegisterNativeAsync of NotificationHub to register channel uri, returned by first with some tags like "Username" and "InstallId" - that is unique per app installation. Then from back-end we send notifications using these tags.
But we have noticed problem - when user hard-resets device, the previous channel registration stays active in notification hub. In that case user receives duplicate notifications by his "Username" tag. "InstallId" doesn't help in that case, as it is changing with new app installation.
We have thought about managing channels server-side. But that will not solve the problem.
Maybe anyone has some suggested work-around?
Also, we don't know what information does PushNotificationChannelManager use when creating new or returning existing channel? Does it use some device information?

I think you can send the backend the device unique Id along with the installation Id. The device id will not change upon hard reset.
private string GetDeviceUniqueID()
{
HardwareToken token = HardwareIdentification.GetPackageSpecificToken(null);
IBuffer hardwareId = token.Id;
HashAlgorithmProvider hasher = HashAlgorithmProvider.OpenAlgorithm("MD5");
IBuffer hashed = hasher.HashData(hardwareId);
string hashedString = CryptographicBuffer.EncodeToHexString(hashed);
return hashedString;
}

Related

Check if user ID exists in Discord server in c#

I'm trying to make a auth link that the user will open then to get the client id from the user and check if the user is exists in a server. I'm not sure what lib should I use would love to get help thank you. I saw this code but this is in JavaScript and I need it in c# + the part of auth link
USER_ID = '123123123';
if (guild.member(USER_ID)) {
// there is a GuildMember with that ID
}```
DSharpPlus is a fairly simple library to use. It'll throw 404 not found when the user isn't found so you'll need to check the ClientErrored event for failure.
var guild = //get current guild somehow
var user = await guild.GetMemberAsync(USERID);
Documentation on GetMemberAsync: https://dsharpplus.emzi0767.com/api/DSharpPlus.Entities.DiscordGuild.html#DSharpPlus_Entities_DiscordGuild_GetMemberAsync_System_UInt64_
Repo: https://github.com/DSharpPlus/DSharpPlus
D#+ vs Discord.Net is DNet will give you more control over handling of events and messages. D#+ is more plug and play kind of deal.

Add 2fa authenticator to user

I have been trying to work out how to enable 2f login with Google Authentication in my Identity server 4 application.
2fa works fine with both email and phone.
if i check
var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
it has two email and phone. I am assuming that this would be the two factor providers that have been set up for this user.
Now if i check _usermanager again there is a field called tokenproviders. Which appears to contain default, email, phone, and authenticator. I assume these are the ones that Asp .net identity is configured to deal with.
I have worked out how to create the secret needed to genreate the QR code for the authecator app. As well has how to build the QR code and to test the code
var code = _userManager.GenerateNewAuthenticatorKey();
var qr = AuthencatorHelper.GetQrCodeGoogleUrl("bob", code, "My Company");
var user = await _signInManager.TwoFactorAuthenticatorSignInAsync(codeFromAppToTestWith, true, false);
if (user == null)
{
return View("Error");
}
Now the problem. I have gone though every method I can find on the user trying to work out how to add another token provider to the user.
How do I assign a new token provider to the user and supply the secret code needed to create the authentication codes?? I am not even seeing any tables in the database setup to handle this information. email and phone number are there and there is a column for 2faenabled. But nothing about authenticator.
I am currently looking into creating a custom usermanager and adding a field onto the application user. I was really hoping someone had a better idea.
From what I can see, you are generating a new authenticator key each time the user needs to configure an authenticator app:
var code = _userManager.GenerateNewAuthenticatorKey();
You should be aware that using GenerateNewAuthenticatorCodeAsync will not persist the key, and thus will not be useful for 2FA.
Instead, you need to generate and persist the key in the underlying storage, if it not already created:
var key = await _userManager.GetAuthenticatorKeyAsync(user); // get the key
if (string.IsNullOrEmpty(key))
{
// if no key exists, generate one and persist it
await _userManager.ResetAuthenticatorKeyAsync(user);
// get the key we just created
key = await _userManager.GetAuthenticatorKeyAsync(user);
}
Which will generate the key if not already done and persist it in the database (or any storage configured for Identity).
Without persisting the key inside the storage, the AuthenticatorTokenProvider will never be able to generate tokens, and will not be available when calling GetValidTwoFactorProvidersAsync.

Telegram API error USER_DEACTIVATED after authentication

I'm using a simple client for Telegram API on C# using TLSharp library.
var appId = ConfigurationManager.AppSettings["appId"];
var appSecret = ConfigurationManager.AppSettings["appSecret"];
var clientPhone = ConfigurationManager.AppSettings["clientPhone"];
...
var session = new FileSessionStore();
client = new TelegramClient(int.Parse(appId), appSecret, session, clientPhone);
await client.ConnectAsync();
if (!client.IsUserAuthorized())
{
hash = await client.SendCodeRequestAsync(clientPhone);
await client.MakeAuthAsync(clientPhone, hash, code);
}
var state = await client.SendRequestAsync<TLState>(new TLRequestGetState());
Here I'm getting exception USER_DEACTIVATED.
So, I tried to get new clean account (with new phone number), login throgth mobile telegram client, after that login to web version, searched some channels, subscribe, sent some messages. After that I tried to login with my client app and at FIRST request got same error.
This issue started to reproduce just this week. Before that I successfully used several test accounts, getting messaged, worked with media and dialogs, no any deactivate errors.
What I'm doing wrong? What limits or policies was broked my application and does exists any way to restore my app?
UPDATE
Tried to register new application from another account. After that, repeat same actions with new phone number and another PC with another IP address - banned after first request.
What is going on? Why can telegram blocks my accounts?

C# Websocket-Sharp - how to identify clients

I use websocket-sharp ( https://github.com/sta/websocket-sharp ) (serveur side only).
I can have many clients applications connected to my websocket server. Each client send an ID (let's call it CLIENT_ID).
I want to know which websocket session is related to CLIENT_ID.
IWebSocketSession expose ID (let's call it SESSION_ID).
What I have tried:
Firstly I have a storage class which store for each SESSION_ID his CLIENT_ID (a simple dictionary).
When I receive a message from a client application, i store SESSION_ID and CLIENT_ID in my dictionary.
So when i want to send a message to all sessions having CLIENT_ID == XXX i can use this dictionary. This works fine ...
BUT sessions are only temporary. A client can use multiple sessions. So for a single client, I will soon have many inputs in my dictionary. When i send a message to all sessions in my dictionnary having CLIENT_ID == XXX, I will send the same message to the same client multiple time.
My question is : How to register unique clients with websocket-sharp ? Which property should I use ?
Edit : Even with a unique client, every 20s it changes ID of the session. It's probably a new session created for ping.
Ok as I find nothing, I kept SESSION_ID but when i register a new item in my dictionary (SESSION_ID => CLIENT_ID) I have to manually delete all "old sessions".
This can be done by checking if session.State == WebSocketState.Open.
It's not perfect but it works.

Windows Phone 8 push notification push channel always creates new channel uri

I wanted to check that my push notification implementation is correct.
Each time I open my app (in actual fact I register the push channel only on a specific page so it's each time I go back and forth from that page) a new push channel URI is created which I store in my mobile services database to send push notifications to. This doesn't seem correct to me as each time the app/page is opened a new push channel URI is generated and so the list of channel URIs just grows and grows for each device that uses my app. I'd assume that you create a push channel, store the channel URI and push to it as needed. I will make note here that I am using raw push notifications.
I understand that push channels will expire every so often but for me it's occurring each time I back out of the app/page and therefore when onNavigateTo is called I find the push channel which does exist and a new channel URI is always created. Is this correct?
My code is as follows:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
registerPushChannel();
}
private void registerPushChannel()
{
// The name of our push channel.
string channelName = "RawSampleChannel";
// Try to find the push channel.
pushChannel = HttpNotificationChannel.Find(channelName);
// If the channel was not found, then create a new connection to the push service.
if (pushChannel == null)
{
pushChannel = new HttpNotificationChannel(channelName);
// Register for all the events before attempting to open the channel.
pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
pushChannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(PushChannel_HttpNotificationReceived);
pushChannel.Open();
}
else
{
// The channel was already open, so just register for all the events.
pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
pushChannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(PushChannel_HttpNotificationReceived);
// code which passes the new channel URI back to my web service
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
pushChannel.Close();
}
So to clarify, the app is opened and the push channel is registered and the channel uri is saved in my web service. The web service then sends notifications to the channel uri. When I exit the app or page and return to it, the push channel is found but a new channel uri is created which I again save to my web service. My channels table in effect just keeps growing and growing.
So is this the way it should work with new channel URIs continually generated? It kind of doesn't make sense to me. I'm not sure how toast and tile notifications work but I'd assume the channel URI needs to be static when the app closes to keep receiving notifications while the app is closed, but perhaps that could be a functionality of bindtotoast and bindtotile and so what I'm doing is correct because it's to do with raw notifications.
You're mostly doing it right.
Push Notifications are a funny thing.
You create a channel, send it to your server and then the server can send until it fails (the channel Uri expires or there's an error).
At which point the app needs to create a new ChannelUri and then UPDATE the value stored for that app/device on the server. The server will then be able to send notifications.
Some important points
When a new channel Uri is requested for one that is still valid you'll get the same one back.
When your ask for a new channel uri and the current one has expired, you'll normally get the same uri returned but the channel will be made live again.
There is no way to know if a channel has expired from within an app without running code like your registerPushChannel method. (Unless you track this on your backend and the app queries the backend.)
There is no way to tell the app that a channel has expired, or tell the user to reopen the app to re-establish a channel connection using the push infrastructure.
The standard way to try and ensure that the channel is always available is to check the channel whenever the app is started.
This is what you're doing, you probably just want to make sure you're updating server records not just adding more.

Categories