FCM Python SDK - Request contains an invalid argument - python-3.x

For my mobile applications (Android and iOS), I am using Firebase Cloud Messaging (FCM) for push notifications.
My backend server, uses the FCM Admin Python SDK to send the notification to a particular device with some additional data. The code responsible for sending the notification is as follows:
import firebase_admin
from firebase_admin import credentials
from firebase_admin import messaging
cred = credentials.Certificate('cert.json')
firebase_admin.initialize_app(cred)
def sendNotification(token, sessionId, authenticationUrl, deviceId):
# This registration token comes from the client FCM SDKs.
registration_token = token
message = messaging.Message(
token=registration_token,
data={
'sessionId': sessionId,
'authenticationUrl': authenticationUrl,
'deviceId': deviceId
},
android=messaging.AndroidConfig(ttl=0, priority='high'),
apns=messaging.APNSConfig(
headers={'apns-priority': '10'},
payload=messaging.APNSPayload(
aps=messaging.Aps(content_available=True)
)
)
)
# Send a message to the device corresponding to the provided registration token.
try:
response = messaging.send(message)
print('Successfully sent message:', response)
except Exception as e:
print(e)
Before, I had the follwing also as part of Aps object but I removed it as the message and body is generated by the mobile application now (depending on mobile language):
alert=messaging.ApsAlert(title='Authentication Request', body='Would you like to authenticate?')
Since removing the ApsAlert, the above code fails randomly with the error:
Request contains an invalid argument.
If I call the same function again without any changes, it succeeds after few attempts and again fails on some runs. There is no common pattern due to which this fails.
Is there a way, I can get some more information regarding the error in order to resolve it?
Maybe, which is the invalid arguement.
Update
Based on #Hiranya's comment, I added some error handling and I was able to determine for which arguement it returns "Invalid arguement".
It does that for registration_token but interestingly, the token is never modified during consecutive runs that fail and succeed.
So, still no clue regarding this behavior.
For info:
Python version: 3.8
firebase-admin version: 4.5.2

Related

Python3 Kraken Exchange Websockets AddOrder not working

I'm trying to send orders through websockets, but I don't know how to receive the response from the websocket as to whether it was successful or not. The site (https://support.kraken.com/hc/en-us/articles/360034936531-WebSocket-API-Trading-addOrder-and-cancelOrder) says that once the order had been sent, there will be a response outlining whether it was successful or not.
I'm just testing the addOrder with the following code:
async def test():
async for ws in websockets.connect("wss://ws-auth.kraken.com/"):
try:
token = generate_token()
request = {"event": "subscribe", "subscription": {"name": "addOrder", "token": token}}
await ws.send(json.dumps(request))
confirm_connection(await ws.recv())
confirm_subscription(await ws.recv())
volume = 0.0001
leverage = 0
ID = '12345'
request = {'event': 'addOrder', 'token': token, 'reqid': ID, 'ordertype': 'market', 'type': 'buy', 'pair': "XBT/USD", 'volume': volume, 'userref': ID, 'validate': 1}
resp1 = await ws.send(json.dumps(request))
resp2 = await ws.recv()
except websockets.ConnectionClosed:
continue
It connects to the websocket, makes a request for a test trade, sends that off. Then when I try to receive a response (line with resp2 = ...) it just says the following:
'{"errorMessage":"Public market data subscriptions are unavailable on this endpoint. Try ws.kraken.com","event":"subscriptionStatus","status":"error","subscription":{"name":"addOrder","token":"X"}}'
How are you supposed to receive the response as to whether Kraken received the trade request or not?
Thanks in advance
I have no experience with kraken websockets addOrder, but I do have experience with kraken addOrder api and kraken ownTrades and openOrders websocket subscriptions.
I'm guessing here, but judging from the error message, it looks like the error message is a response to a previous websocket subscription call you made requesting to subscribe to a channel data feed (not sure which one though).
With websockets, upon connection, you should get a systemStatus response message. In it, it contains the status ("online" is what you want to check for).
Next, depending on the subscription, you may receive a snapshot message pertaining to that service if it's online. That message will contain recent trade fills (ownTrades subscription), or currently open order (openOrders subscription). I haven't touched individual asset pair subscriptions, but I'm guessing recent activity there will be communicated as well.
I have no idea if anything I've stated herein will help you, but I do know this will definitely help you...
Contact kraken support by logging into your kraken account and then click on Support. I always open a support ticket (no chat, etc.) so that I can provide them with as much detail as I can including what I'm doing, how I'm doing it, and all error messages I'm getting back from them.
To date, they have responded in less than 24 hours and they've always given me very specific answers to my questions (there have been many questions). Overall, I would rate their support minimally 4.5 out of 5 stars.
Good luck.
I figured it out after some time, so this is for anyone else who has this issue.
There were no issues with websocket subscription, it was working as intended. Kraken does a weird thing where they send an error through the websocket, but it really is just a message and can be ignored. The websocket remains open and operational afterwards, so you just need to ignore the first response from the websocket.

Exception: 401 Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential

I've seen a few people over the years facing similar issue but I haven't found much regarding my case.
I have a backend built with python3.
I am using firebase_admin as a library to connect to Firebase Cloud Firestore.
I then commit my code to Github and using Github Actions
I am deploying the docker container to Google Cloud Run.
This all works fine for some time
Some time later throws the following exception: Exception: 401 Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.
What am I doing wrong?
Should I connect every time I call the function? (move the db initialization in each function call)
Feels like the token expired. Can I refresh it somehow?
Python code:
from firebase_admin import firestore, initialize_app
initialize_app()
db = firestore.client()
def get_info_from_firestore(name: str:
try:
data = db.collection(u'data').where(u'title', u'==', name).stream()
for rating in ratings:
return rating.to_dict()
return None
except Exception as e:
logging.warning(Exception: {e}')
return None
And this file is imported from my root python file that's using Flask.
Edit: One final thing that might help, if I redeploy my container without any changes it all works again.
Likely this is happening due to time drift: time in docker significatly differs realtime. After restart time is in sync but after a while it drifts. Google does not like it. See more info about this WSL/container issue here https://github.com/microsoft/WSL/issues/4245 and here https://github.com/docker/for-win/issues/4526

Add authentication to Azure Device Streams

We want to use IOT hub and use device streams to proxy our internal Web API for maintenance purposes. This works quite fine, but we also need some kind of authorization. The shared access policy is not fine-grained enough for this purpose.
I would rather use some kind of authentication token (JWT) to pass in the request that can be checked by the device itself. If the token can be validated and the use has the proper rights, then the connection is accepted and otherwise it's reject. The only value that can be configured is the name, so I need to encode the token in the name. The client code could look something like this:
Client code
var deviceStreamRequest = new DeviceStreamRequest(streamName: "WebAPI?token=<JWT-token here>");
var result = await serviceClient.CreateStreamAsync(deviceId, deviceStreamRequest, cancellationToken).ConfigureAwait(false);
Device code
var streamRequest = await deviceClient.WaitForDeviceStreamRequestAsync(cancellationToken).ConfigureAwait(false);
if (streamRequest != null)
{
var token = GetTokenFromName(streamRequest.Name);
if (!CheckClaim(token, "WebAPI"))
{
await deviceClient.RejectDeviceStreamRequestAsync(streamRequest, cancellationToken).ConfigureAwait(false);
return;
}
await deviceClient.AcceptDeviceStreamRequestAsync(streamRequest, cancellationToken).ConfigureAwait(false);
// ...
}
The DeviceStreamRequest class does contain an AuthenticationToken, but it seems to be the authentication token that is used to connect back to IOT using the websocket and cannot be used for other purposes.
I there a better way to pass the token then using the name?
The current version of the Microsoft.Azure.Devices.DeviceStreamRequest didn't allow to populate a request payload to the device like we have in the device direct method. The request payload is the best place for sending an additional (or business) data to the device related to the streaming preprocessing such as the B2B decisions, etc.
Note, that using a streamName for passing your token is not the correct way, see the following code snippet from the .Net Reflector:
public override Task<DeviceStreamResponse> CreateStreamAsync(string deviceId, DeviceStreamRequest deviceStreamRequest, CancellationToken cancellationToken)
{
return this.CreateStreamAsync(GetDeviceStreamUri(deviceId, deviceStreamRequest.StreamName), deviceStreamRequest, cancellationToken);
}
where, the GetDeviceStreamUri has the following implementation:
private static Uri GetDeviceStreamUri(string deviceId, string streamName)
{
deviceId = WebUtility.UrlEncode(deviceId);
object[] args = new object[] { deviceId, streamName };
return new Uri("/twins/{0}/streams/{1}?api-version=2018-08-30-preview".FormatInvariant(args), UriKind.Relative);
}
As you can see the above Uri, there is already hardcoded query parameter such as ?api-version=2018-08-30-preview
However, there is a workaround for your solution based on the using an underlying communication (no using the SDK package), for instance, the REST APIs. Note, that this feature is still in the preview.
For demonstration of the iot device streaming, I am using my Azure IoT Hub Tester.
The following screen snippet shows the invoker POST request to the IoT Hub for device streaming:
As you can see, the Microsoft.Azure.Devices.DeviceStreamRequest can handled only the stream name and two headers such as iothub-streaming-response-timeout-in-seconds and iothub-streaming-connect-timeout-in-seconds.
Posting this reqest, the IoT Hub will send the message to the device. The following screen snippet shows a received message in my virtual MQTT device1:
Now, the device1 can evaluate a message payload to make a decision for either the accepting (code 202) or rejecting (code 4xx, etc.) the streaming process. Note, that there is a response time limit (in my example is 15 seconds) from the invoker call.
Once, the device accepted this streaming process, the invoker will receive the response from the IoT Hub with details in the headers for creating a websocket communication and payload from the device. The following is an example of the headers:
iothub-streaming-is-accepted: True
iothub-streaming-url: wss://centralus.centralus-001.streams.azure-devices.net:443/bridges/ih/rk2019-iot/d/device1/sid/****
iothub-streaming-auth-token: ***
iothub-streaming-ip-address: 0.0.0.0
Based on that, the invoker can evaluate a device response payload before creating a websocket communication.

NodeJS Azure Functions used as a Messenger Bot return an mscorlib error

I'm trying to use Azure Functions as a Messenger bot server using a Generic Webhook. The problem I'm running into is that even running this simple code (most of it is commented out to try & figure out the issue) results in an error (below the code):
module.exports = function (context, data) {
context.log('Webhook was triggered!');
context.res = {
status: 403,
body: ''
}
context.done();
}
Function completed (Failure,
Id=fb0f2178-8b98-4163-a5ae-7ab68eff47cd)
Exception while executing function: Functions.StriverMessenger.
mscorlib: The given key was not present in the dictionary.
Why is this error occurring and how do I get this to work? If I fake out the querystring entries in the run mode inside Azure, the function appears to work as coded. The error occurs when trying to send a Verify request to the Azure Function from Facebook Developer, specifically in Messenger's Webhook setup.
This happens when an empty (or non-json) body is sent to a Function with type WebHook. The handling is poor, and we are improving it per https://github.com/Azure/azure-webjobs-sdk-script/issues/849. This should be deployed within a week and you can then verify.

Azure Push Notification Works Randomliy

I have mobile application which uses a backend services to register to Azure push notification. Things were working fine until 4 days ago where the most notifications are not delivered to the application.
I'm using Service Bus Queue and WebJob to send the notification and I can see things executed successfully for Android but the notifications most of the time doesn't deliver to the app and the notification State equals Enqueued and Success equals 0 and Failure equals 0
I updated Microsoft.ServiceBus to the latest version but that didn't resolve the issue.
Last thing, Apple notifications used to work successfully but now they are throwing exception "The remote server returned an error: (400) Bad Request. The supplied notification payload is invalid"
Does anyone face similar issues?
I have experienced the same issue when pushing notifications to iOS devices via Azure's Notification Hubs. I received the same error message when calling the "SendAppleNativeNotificationAsync" method on the hub.
I made sure that I had no illegal characters in my message by replacing "\" and "'". After reading a few posts regarding issues with max limit on notifications, we decided to limit our message size to 150 characters (a magic number, we didn't do any research to find out exactly how big a push notification message is allowed to be).
I also changed how the JSON payload was created, and I'm now using Newtonsoft.Json.Linq to create a JSON object with my payload. I previously created a simple json string for the payload, something like this :
var apnsMessage = "{\"aps\":{\"alert\":"+message+", \"sound\" : \"default\", \"badge\" : 1}}";
Now, my JSON object is created as so:
var jsonPayload = JObject.FromObject(new
{
aps = new { alert = message.Replace("\"", "").Replace("'", "") },
sound = "default",
badge = 1
});
and I send the notification like this:
await Hub.SendAppleNativeNotificationAsync(jsonPayload.ToString());
Hope this helps you (or anyone else with the same issue) :)
EDIT:
Here is a simple helper for trimming/truncating strings :)
private static string GetTrimmedAndTruncatedString(string source, int length)
{
return source.Length > length ? source.Substring(0, length) + "..." : source;
}
/Isa

Resources