Recent

Author Topic: Free Pascal and sending push-notifications via FCM  (Read 4434 times)

JohnvdWaeter

  • Full Member
  • ***
  • Posts: 185
    • http://www.jvdw.nl
Free Pascal and sending push-notifications via FCM
« on: May 07, 2024, 07:54:36 pm »
Hi All,
I recall having read somewhere that someone is working on using Free Pascal to send push-notifications to a Google Firebase server.
I wrote a freepascal linux service that handled this for many years, but now Google is switching to a new protocol (v1).

Their doc doesn't help me, I'm stuck.

Is someone working on this?
tia, John

Thaddy

  • Hero Member
  • *****
  • Posts: 16177
  • Censorship about opinions does not belong here.
Re: Free Pascal and sending push-notifications via FCM
« Reply #1 on: May 07, 2024, 08:48:31 pm »
Usually this is picked up by regenerating the google api package, but I am not sure.
It is pretty much automated and there are instructions on how to do that yourself.
( If I am wrong the term is Michael Automata )
If I smell bad code it usually is bad code and that includes my own code.

rvk

  • Hero Member
  • *****
  • Posts: 6584
Re: Free Pascal and sending push-notifications via FCM
« Reply #2 on: May 07, 2024, 09:53:23 pm »
What's the problem you are experiencing when switching to
https://fcm.googleapis.com/v1/projects/xxx ?

I see I still have the legacy http in my small php script so I guess I have to switch soon  ::)

https://firebase.google.com/docs/cloud-messaging/migrate-v1

JohnvdWaeter

  • Full Member
  • ***
  • Posts: 185
    • http://www.jvdw.nl
Re: Free Pascal and sending push-notifications via FCM
« Reply #3 on: May 08, 2024, 12:55:38 pm »
Yes, the legacy protocol worked great for years, and still does.
The new V1 protocol gives me headaches....
I try (in a GUI):

Code: Pascal  [Select][+][-]
  1.  
  2. if radiobutton1.Checked then ato:=edit1.Text; // iOS FCMDevicetoken
  3. if radiobutton2.Checked then ato:=edit2.Text; // Android FCMDevicetoken
  4.  
  5.    TheMessage:='{"message": {'+
  6.                               '"token":"'+ato+'",'+
  7.                               '"notification":{'+
  8.                                                '"title":"Notification title",'+
  9.                                                '"body":"Notification body" '+
  10.                                              '}}}';
  11.  
  12.  projectid   := 'ellip.........6407';
  13.  access_token  := '5663a6ca0c115f787.........72b76af6c2dd5';
  14.  topost  := 'https://fcm.googleapis.com/v1/projects/'+projectid+'/messages:send HTTP/1.1';
  15.  
  16.  memo2.Lines.Add(topost);
  17.  
  18.  IdHTTP := TIdHTTP.Create(nil);
  19.   try
  20.     IdHTTP.ProtocolVersion     := TidHttpProtocolversion.pv1_1;
  21.     idHttp.HTTPOptions         := [hoKeepOrigProtocol,hoForceEncodeParams];
  22.     IdHTTP.Request.ContentType := 'application/json';
  23.     IdHTTP.Request.Charset     := 'UTF-8';
  24.     idhttp.HandleRedirects     := True;
  25.     IdHTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer '+access_token;
  26.  
  27.     try
  28.      JsonToSend := TStringStream.Create(TheMessage, TEncoding.UTF8);
  29.      response   := IdHTTP.Post(topost, jsontosend);
  30.      Memo2.Lines.Add('resp:'+response);
  31.  
  32.     except
  33.      on E: EIdHTTPProtocolException do
  34.       begin
  35.        Memo2.Lines.add(IntToStr(E.ErrorCode) + ' ' + E.Message);
  36.       end;
  37.  
  38.     on E:Exception do
  39.      begin
  40.       Memo2.Lines.add('Error: '#13 + E.ClassName + #13 + E.Message);
  41.      end;
  42.     end;
  43.  
  44.   finally
  45.     IdHTTP.Free;
  46.   end;
  47.  
  48.   jsonToSend.Free;  
  49.  
  50.  

But this gives me an error: 400 HTTP/1.0 400 Bad Request

rvk

  • Hero Member
  • *****
  • Posts: 6584
Re: Free Pascal and sending push-notifications via FCM
« Reply #4 on: May 08, 2024, 01:30:42 pm »
Code: Pascal  [Select][+][-]
  1.  topost  := 'https://fcm.googleapis.com/v1/projects/'+projectid+'/messages:send HTTP/1.1';
  2.  
I haven't tried yet but above line is definitely wrong.
The HTTP/1.1 shouldn't be there. It isn't part of the URL !!

Try it without.
If it doesn't work, I'll create a working example here (but not with Indy but with fphttp).

JohnvdWaeter

  • Full Member
  • ***
  • Posts: 185
    • http://www.jvdw.nl
Re: Free Pascal and sending push-notifications via FCM
« Reply #5 on: May 08, 2024, 01:44:03 pm »
If I remove HTTP/1.1 I get:

401 HTTP/1.1 401 Unauthorized

rvk

  • Hero Member
  • *****
  • Posts: 6584
Re: Free Pascal and sending push-notifications via FCM
« Reply #6 on: May 08, 2024, 02:23:41 pm »
If I remove HTTP/1.1 I get:

401 HTTP/1.1 401 Unauthorized

Quote
Code: [Select]
access_token  := '5663a6ca0c115f787.........72b76af6c2dd5';
How did you get that access_token?
Shouldn't this be in the form of ya29.... ??

The new API uses short lived access tokens (which you should retrieve before sending a message).

Normally a library would do this for you but if you are calling the API bare boned, you'll need to do this yourself.

rvk

  • Hero Member
  • *****
  • Posts: 6584
Re: Free Pascal and sending push-notifications via FCM
« Reply #7 on: May 08, 2024, 02:35:09 pm »
BTW. This should also be clear from the body that's returned...  :P

Quote
{
  "error": {
    "code": 401,
    "message": "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.",
    "status": "UNAUTHENTICATED"
  }
}

O, and BTW. I got the example for TFCMClient in FPC working.

.\fpc\packages\fcl-web\examples\fcm\cli\sendmsg.lpi

It will retrieve an access_token and send a message (when given a correct service.json).

sendmsg --service-account=xxx.json --title=test --body=body --recipient="xxx" --log=test.txt
« Last Edit: May 08, 2024, 03:07:07 pm by rvk »

JohnvdWaeter

  • Full Member
  • ***
  • Posts: 185
    • http://www.jvdw.nl
Re: Free Pascal and sending push-notifications via FCM
« Reply #8 on: May 08, 2024, 03:46:09 pm »
I never saw a token starting with ya29...
So many keys, certificates, tokens...

But... if you have it working... :)
 
Does this path

.\fpc\packages\fcl-web\examples\fcm\cli\sendmsg.lpi

point to github repository?

rvk

  • Hero Member
  • *****
  • Posts: 6584
Re: Free Pascal and sending push-notifications via FCM
« Reply #9 on: May 08, 2024, 03:54:49 pm »
But... if you have it working... :)
Does this path
.\fpc\packages\fcl-web\examples\fcm\cli\sendmsg.lpi
point to github repository?
It should be in your FPC (or Lazarus) installation.

But it could be that it's only in trunk for now (I see it was probably added one month ago).

https://gitlab.com/freepascal.org/fpc/source/-/tree/main/packages/fcl-web/examples/fcm

Google didn't make it easier  ;)
You would need to download the service json (which is the easiest part).
For the communication you would first need to retrieve an access token (which would be valid for one hour).
This is done by constructing a JWT and encoding it and passing it to https://oauth2.googleapis.com/token

The you get an access_token which you can use with the code you already got.

This is from the log from the example project (anonymized).

Quote
--------------------------------------------------------------------------------
Request : POST https://oauth2.googleapis.com/token
Headers:
Content-Type:application/x-www-form-urlencoded
Body:
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyAid12345ABCD
Trying multiple protocols.
--------------------------------------------------------------------------------
Response : 200 : OK
Headers:
Content-Type: application/json; charset=UTF-8
Vary: X-Origin
Vary: Referer
Date: Wed, 08 May 2024 13:04:43 GMT
Server: scaffolding on HTTPServer2
Cache-Control: private
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Accept-Ranges: none
Vary: Origin,Accept-Encoding
Connection: close
Transfer-Encoding: chunked
Body:
{"access_token":"ya29.c.c0AY_VpZhwxHJSG12345abcd_very_long_token","expires_in":3599,"token_type":"Bearer"}
--------------------------------------------------------------------------------
Request : POST https://fcm.googleapis.com/v1/projects/xxxx-xxxx-12345/messages:send
Headers:
Accept:application/json
Content-Type:application/json
Authorization:Bearer ya29.c.c0AY_VpZhwxHJSG12345abcd_very_long_token
Body:
{ "message" : { "notification" : { "title" : "test", "body" : "body" }, "android" : { "notification" : {} }, "webpush" : {}, "apns" : {}, "fcm_options" : {}, "token" : "ejEw2lxxxxx" } }
Trying multiple protocols.
--------------------------------------------------------------------------------
Response : 200 : OK
Headers:
Content-Type: application/json; charset=UTF-8
Vary: X-Origin
Vary: Referer
Date: Wed, 08 May 2024 13:04:44 GMT
Server: scaffolding on HTTPServer2
Cache-Control: private
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Accept-Ranges: none
Vary: Origin,Accept-Encoding
Connection: close
Transfer-Encoding: chunked
Body:
{
  "name": "projects/xx-xx-1234/messages/0:1234%31abc"
}

JohnvdWaeter

  • Full Member
  • ***
  • Posts: 185
    • http://www.jvdw.nl
Re: Free Pascal and sending push-notifications via FCM
« Reply #10 on: May 08, 2024, 04:48:52 pm »
Ok, thanks for the link. I have this sendmsg project, but it needs units fpfcmclient and fpfcmtypes.
Where to find them?
Sorry, I'm a little (?) ignorant when it comes to using gitlab contributions...

rvk

  • Hero Member
  • *****
  • Posts: 6584
Re: Free Pascal and sending push-notifications via FCM
« Reply #11 on: May 08, 2024, 04:51:33 pm »
Ok, thanks for the link. I have this sendmsg project, but it needs units fpfcmclient and fpfcmtypes.
Where to find them?
Sorry, I'm a little (?) ignorant when it comes to using gitlab contributions...
https://gitlab.com/freepascal.org/fpc/source/-/tree/main/packages/fcl-web/src/fcm

I'm not sure if you can use those without changes in the rest of FPC.

JohnvdWaeter

  • Full Member
  • ***
  • Posts: 185
    • http://www.jvdw.nl
Re: Free Pascal and sending push-notifications via FCM
« Reply #12 on: May 08, 2024, 05:56:29 pm »
Not immediately, there's a chain of dependencies....

rvk

  • Hero Member
  • *****
  • Posts: 6584
Re: Free Pascal and sending push-notifications via FCM
« Reply #13 on: May 08, 2024, 07:59:50 pm »
I hacked my send.php really fast to see if it could work and, besides the link and color properties I have, it worked fine.

Code: PHP  [Select][+][-]
  1. function enc($data) {
  2.   $base64 = base64_encode($data);
  3.   $base64Url = strtr($base64, '+/', '-_');
  4.   return rtrim($base64Url, '=');
  5. }
  6.  
  7. function create_jwt($payload) {
  8.   $base64UrlHeader = enc(json_encode(["typ" => "JWT", "alg" => "RS256"]));
  9.   $base64UrlPayload = enc(json_encode($payload));
  10.   $fp=fopen("jwtRS256.key", "r");
  11.   $privKey=fread($fp,8192);
  12.   fclose($fp);
  13.   $private=openssl_get_privatekey($privKey);
  14.   openssl_sign("$base64UrlHeader.$base64UrlPayload", $signature, $private, "sha256WithRSAEncryption");
  15.   openssl_free_key($private);
  16.   $base64UrlSignature = enc($signature);
  17.   return "$base64UrlHeader.$base64UrlPayload.$base64UrlSignature";
  18. }
  19.  
  20. $payload = [
  21.   "iss" => "firebase-adminsdk-123@xxx-123.iam.gserviceaccount.com",
  22.   "aud" => "https://oauth2.googleapis.com/token",
  23.   "exp" => time() + 3600, // Token expiration time (1 hour)
  24.   "iat" => time(),
  25.   "scope" => "https://www.googleapis.com/auth/firebase.messaging"
  26. ];
  27.  
  28. $jwt = create_jwt($payload);
  29. $data="grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=".$jwt;
  30.  
  31. $headers = array(
  32.   'Content-Type: application/x-www-form-urlencoded'
  33. );
  34.  
  35. $ch = curl_init();
  36. curl_setopt( $ch,CURLOPT_URL, 'https://oauth2.googleapis.com/token' );
  37. curl_setopt( $ch,CURLOPT_POST, true );
  38. curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
  39. curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );
  40. curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );
  41. curl_setopt( $ch,CURLOPT_POSTFIELDS, $data );
  42. $result = curl_exec($ch );
  43. curl_close( $ch );
  44. // echo $result;
  45.  
  46. $arr=json_decode($result, true);
  47. $access_token=$arr['access_token'];

I got a valid access_token with which I could send a message.
I didn't do this in FPC yet because I needed it in PHP for my server.
But create a JWT is just calling openssl with the correct private key (you should have in your downloaded service.json).

JohnvdWaeter

  • Full Member
  • ***
  • Posts: 185
    • http://www.jvdw.nl
Re: Free Pascal and sending push-notifications via FCM
« Reply #14 on: May 08, 2024, 10:29:32 pm »
Nice job! But I'll await the FPC. I guess I'm too old to learn ans understand all this.

 

TinyPortal © 2005-2018