I want to send a push notification from an android app direct to an android endpoint using amazon SNS. I'd like to know how to do that if I have only the GCM token of the endpoint (if it is impossible, what I have to have to do so?). I have to know how to register the endpoint on amazon SNS from the endpoint app too, if it is necessary. I am using Android Studio. I am newbie on app development and need this as soon as possible!!
Thank you
Andre
you can use the following method to register in amazon sns from android device.Before u go for registration you have to get
1.access_key_id
2.secret_access_key
3.application Arn
4.API key from gcm
then use following code:
private String createEndpoint(String token) {
String endpointArn = null;
try {
System.out.println("Creating endpoint with token " + token);
CreatePlatformEndpointRequest cpeReq = new CreatePlatformEndpointRequest().withPlatformApplicationArn(applicationArn).withToken(token);
CreatePlatformEndpointResult cpeRes = client.createPlatformEndpoint(cpeReq);
endpointArn = cpeRes.getEndpointArn();
} catch (InvalidParameterException ipe) {
String message = ipe.getErrorMessage();
System.out.println("Exception message: " + message);
Pattern p = Pattern.compile(".*Endpoint (arn:aws:sns[^ ]+) already exists " + "with the same Token.*");
Matcher m = p.matcher(message);
if (m.matches()) {
// the endpoint already exists for this token, but with
// additional custom data that
// CreateEndpoint doesn't want to overwrite. Just use the
// existing endpoint.
endpointArn = m.group(1);
} else {
// rethrow exception, the input is actually bad
throw ipe;
}
}
storeEndpointArn(endpointArn);
return endpointArn;
}
Related
I am having problem sending notification to specific devices with FCM.
This is how I get the specific device ID
Add Class in Android Project: FirebaseMessagingServiceDelegate.cs
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseMessagingServiceDelegate : FirebaseMessagingService
{
public async override void OnNewToken(string p0)
{
base.OnNewToken(p0);
var instanceIdResult = await FirebaseInstanceId.Instance.GetInstanceId().AsAsync<IInstanceIdResult>();
var token = instanceIdResult.Token;//(Token Devices)
}
}
Each time the user opens the App: var token = instanceIdResult.Token; will be changed. So every time I have to update the token on my server? Does this mean I also create a Class on Project iOS?
And this is how I send notifications to specific device:
PageOne.xaml.cs
protected void SendNotify()
{
// This registration token comes from the client FCM SDKs.
var registrationToken = "Token Devices";
// See documentation on defining a message payload.
var message = new Message()
{
Token = registrationToken,
Notification = new Notification()
{
Title = "Test from code",
Body = "Here is your test!"
}
};
// Send a message to the device corresponding to the provided
// registration token.
string response = FirebaseMessaging.DefaultInstance.SendAsync(message).Result;
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);
}
I received the error: Notification does not contain a definition for "Body"
I searched and found this article: firebase send notification from server c#. However I want to send directly from Xamarin App.
Hoping for any help. Thank you!
I am trying to get notifications form stripe about the events occured. This is the webhook endpoint which I used. The URL must be publicly accessed. When consider security, is this enough or should I use any other approach?
[HttpPost("WebHook/{id}")]
public async Task<IActionResult> WebHook(int id)
{
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
Event stripeEvent;
try
{
//Get webhook secret
string webHookSecret = XXXX;
//Construct stripe Event
stripeEvent = EventUtility.ConstructEvent(
json,
Request.Headers["Stripe-Signature"],
webHookSecret
);
}
catch (Exception ex)
{
LoggingUtil.LogError(ex, ex.Message);
return BadRequest();
}
}
The webhook signature verification alone is not enough, if only because Stripe uses message authentication with a shared secret rather than asymmetric cryptography digital signatures. If you don't have the paranoid intention of building a bulletproof server, you can start with Stripe's security recommendations. Trivial IP address filtering can make your URL not so "publicly accessible".
I have this scenario: Xamarin.Forms App connected with Web Api 2. I make all requests and get the data i want. Now when the session token expires, i need to refresh the token but don't logout the user. The user don't need to know when token is refreshed. How to organize this, add in every request if statement when i send it and check if token expires.
This is one of my requests:
public async Task<User> GetProfileSetup()
{
try
{
if (CrossConnectivity.Current.IsConnected)
{
string token = DependencyService.Get<ISharedFunctions>().GetAccessToken();
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
var response = await client.GetAsync(#"api/Profile/GetProfilSetup");
if (response.IsSuccessStatusCode)
{
string jsonMessage;
using (Stream responseStream = await response.Content.ReadAsStreamAsync())
{
jsonMessage = new StreamReader(responseStream).ReadToEnd();
}
User user = JsonConvert.DeserializeObject<User>(jsonMessage);
return user;
}
else
{
var m = response.Content.ToString();
return null;
}
}
else
{
return null;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
string error = ex.Message;
return null;
}
}
P.S I have Methods for GetToken and RefreshToken in my Api and they are working, just how to organize Refreshing ?
It really depends on what libraries are you using on your project.
But let's say you're using plain c# to handled your HTTP calls.
[OPTION 1] Polly
I can recommend you looking at Polly
It's a great library with a lot of features. You can use the Retry policy to handled expired tokens:
var _unauthorizedPolicy = Policy
.Handle<Exception>(ex => ex.StatusCode == HttpStatusCode.Unauthorized) // check here for your exception to be the right one
.RetryAsync(3, async (exception, retryCount, context) =>
{
try
{
var token = await _authService.RefreshToken();
// save the new token or whatever you need to store it
}
catch (Exception ex)
{
// RefreshToken failed, you should probably sign out the user
SignOut();
}
});
What this does is that Polly will try to execute your normal HTTP call and in case it fails and the cause is specified in Handle, then a retry mechanism is fired that will try to refresh the token and then retry your request. In the end, in case the token cannot be refreshed, you sign out the user. Of course, all this can be customized, check Polly's documentation is pretty well written.
Please note that inside Handle<T> you must put the right exception. I just used Exception as a placeholder since I'm not sure what Exception is thrown in your case.
Then you would call your method with this policy:
var result = await _unauthorizedPolicy.ExecuteAsync(() => GetProfileSetup())
And you can reuse that policy for any call, no need to create it every time.
[OPTION 2] DelegatingHandler
I will like here another StackOverflow answer:
How to Refresh a token using IHttpClientFactory
Basically you can intercept every HTTP call made via a HttpClient and refresh/add a token to your requests.
Note that that answer does not obligate you to use IHttpClientFactory, it also works for a simple HttpClient.
Also a little bit off-topic. You might want to look up for libraries to handle htt calls such as Retrofit. It will really reduce the amount of boilerplate code.
We're developing a cross platform (Android and iOS) application using Xamarin.Forms. Up to now, we managed to get the app working fine, so it's cool !
We've included some push notifications in our app, using Azure Notification Hub, GCM (for android) and APNS (for iOS). And it works almost fine !
Actually, we just have a last problem : everything is OK for Android, and we can register to push notifications using iOS too, but we can't add some tags to our registrations.
Indeed we need to be able to send a push notification to one user, or one group of users instead of to everyone. To do this, we are doing that in a method of our web api :
if (user.DeviceType.Equals("Android"))
{
registration = new GcmRegistrationDescription(handles.Handle);
}
else
{
registration = new AppleRegistrationDescription(handles.Handle);
}
registration.Tags = new HashSet<string>();
registration.Tags.Add("usermail:" + user.Email);
registration.Tags.Add("userid:" + user.Id);
registration.Tags.Add("userdevice:" + user.DeviceType);
registration.Tags.Add("usertype:" + tag);
registration.RegistrationId = handles.RegistrationId;
await NotificationHelper.Hub.CreateOrUpdateRegistrationAsync(registration);
And for the given Handle, we retrieve it this way in Android :
protected override void OnRegistered(Context context, string registrationId)
{
[...] //the registration id is given in args
}
and this way in iOS :
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
[...]
var DeviceToken = deviceToken.Description;
if (!string.IsNullOrWhiteSpace(DeviceToken))
{
DeviceToken = DeviceToken.Trim('<').Trim('>');
}
UserInformations.Handles.RegistrationId = DeviceToken.Replace(" ", "").ToUpper();
[...]
}
Everything works fine in Android (I'm able to add tags) but I got an error for iOS. The line
await
NotificationHelper.Hub.CreateOrUpdateRegistrationAsync(registration);
is generating an exception, telling me that my registrationId is "not valid anymore". You can notice that I remove spaced in my registrationId for iOS because if I don't, I got another error, telling me that my registrationID contains non-hexadecimal characters.
I don't know what to do to fix this, do I retrievea wrong registrationId in iOS, or is the way to add tags differents for APNS ?
Thanks for your help !
EDIT : I noticed that the device token has to be in uppercase. But surprisingly enough, I got the same error. Here are 2 screenshots to help you understand :
So you can see that in my registration, what I got in DeviceToken and what I got in RegistrationId are the same... I don't know what to do :/
There's actually a lot of documentation and thread posts online that tell you to adjust the device token that you get from the iOS method 'RegisteredForRemoteNotifications'. However if you look at the official documentation this is not the correct way of doing it.
Below is a snippet from our 'RegisteredForRemoteNotifications' method, as you can see we don't do anything with the device token, give it a shot and let me know if this solves your problem.
if (oldDeviceToken != null)
{
if (oldDeviceToken.ToString() != deviceToken.ToString())
{
try
{
Hub.UnregisterAllAsync(oldDeviceToken, (error) =>
{
//check for errors in unregistration process.
if (error != null)
{
TestingLogs.ApplicationLog.AppendFile(DateTime.Now.ToString() + " : " + "[PNS EXCEPTION] - Exception has been hit! - Message: " + error + " | Source: " + "Unregistering old device token against the notification hub.");
//exit out of the code here because we can't keep our hub clean without being able to remove the device from our registration list.
return;
}
else
{
ShouldComplete = true;
}
});
}
catch (Exception genEx)
{
TestingLogs.ApplicationLog.AppendFile(DateTime.Now.ToString() + " : " + "[PNS EXCEPTION] - Exception has been hit! - Message: " + genEx.Message + " | Source: " + genEx + Environment.NewLine + Environment.NewLine);
}
}
}
else
{
// Store current device token
bool res = await ApplicationSettings.StoreDeviceToken(deviceToken);
}
// Check if we need to perform our initial registrations
if (ShouldComplete)
{
NSSet RegisteredTags = await ApplicationSettings.RetrieveUserTags();
if (RegisteredTags == null)
{
RegisteredTags = new NSSet("AppleDevice");
}
//Register the device against the notification hub keeping the details accurate at all times.
Hub.RegisterNativeAsync(deviceToken, RegisteredTags, (errorCallback) =>
{
if (errorCallback != null)
{
TestingLogs.ApplicationLog.AppendFile(DateTime.Now.ToString() + " : " + "[PNS EXCEPTION] - Exception has been hit! - Message: " + errorCallback + " | Source: " + "Registering device token against the notification hub.");
}
else
{
if (deviceToken != null)
{
NSUserDefaults.StandardUserDefaults.SetString("Completed", "InitialTagRegistration");
NSUserDefaults.StandardUserDefaults.Synchronize();
}
}
});
}
I am integrating with WebSockets in my Spring MVC application. The authentication mechanism for my application is OAuth.
I was able to pass my OAuth token in connection string when connecting to SockJS:
var webSocketUrl = '/websocket' + '?access_token=' + auth.access_token;
var socket = new SockJS(webSocketUrl);
var stompClient = Stomp.over(socket);
Now I can send messages and subscribe to STOMP channels:
stompClient.connect({}, function(frame) {
stompClient.subscribe('/topic/greetings', function(greeting){
console.log(greeting);
});
stompClient.send("/app/hello", {}, JSON.stringify('John'));
});
In my backend I am able to get user principle injected to my STOMP controller methods (which means that Spring understands that there is an OAuth token in connection string):
#Controller
public class MyWebsocketsController {
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public String greet(String name, Principal authorizedUser) {
return "Hello, " + name + ", you have authorized as " + authorizedUser.getName();
}
}
Now I would like to require user authorization on all messages and subscriptions, i.e. I would like to make sure that all calls to web sockets return 403 error code if no valid token was provided when connecting to SockJS.
I add this security configuration to my project:
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpTypeMatchers(CONNECT, HEARTBEAT, UNSUBSCRIBE, DISCONNECT).permitAll()
.simpDestMatchers("/app/**").authenticated()
.simpSubscribeDestMatchers("/topic/**").authenticated()
.simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll()
.anyMessage().denyAll();
}
}
But it does not seem to do the job. If I remove access token from connection string, I am still able to send messages to controller and to subscribe to channel.
// This stil works:
var webSocketUrl = '/websocket'; // + '?access_token=' + auth.access_token;
Of course, now I can't get the user principle in my controller, but except for this web sockets work fine.
I would appreciate any ideas how to make this thing work or any explanation why web sockets security configuration is not working for my case. What am I missing? Thanks.