parse-community / node-apn Goto Github PK
View Code? Open in Web Editor NEWThis project forked from node-apn/node-apn
Apple Push Notification module for Node.js
License: Other
This project forked from node-apn/node-apn
Apple Push Notification module for Node.js
License: Other
I am facing an issue using this package
The notification is successfully sent to the given device token by your package but not receiving notification on the device is there any delay problem or anything else
I have provided my code Please help me to solve this problem as soon as possible
Looking forward to hearing from you guys
Thanks
I've been playing around with the library and it seems like the HTTP stream never gets the on('end')
event when there's a error response from APNs, i.e. 400 Missing Device Token and would just give a timeout error.
With a debugger I was able to see the errors be correctly received in the headers and the response
https://github.com/parse-community/node-apn/blob/master/lib/client.js#L150
But afterwards it nevers goes into the request.on('end') part:
https://github.com/parse-community/node-apn/blob/master/lib/client.js#L161
It only goes into the timeout handler:
https://github.com/parse-community/node-apn/blob/master/lib/client.js#L207
I've did the same test in the official node-apn package and it was returning error states correctly.
jsonwebtoken
8.5.1 has security vulnerability GHSA-27h2-hvpr-p74q. Please upgrade to 9.0.0.
I am not sure if this is intended behavior, or a bug, but I started running into an issue that was similar to the issue reported here: #59 (comment).
Basically, when I create a notification like so:
let notification = new apn.Notification();
notification.payload = {
aps: data
};
I am able to send that notification and I get a success response like so:
{"sent":[{"device":"test_device_id"}],"failed":[]}
However, the notification never shows up on my device.
If I manually set the aps
property, the notification will show up on the device:
let notification = new apn.Notification();
notification.payload = {
aps: data
};
notification.aps = data;
In the code: https://github.com/parse-community/node-apn/blob/master/lib/notification/index.js#L127, it looks like if the aps
property is never set, the code is setting payload.aps
to undefined
. There is also a unit test to make sure the aps
property is not present when the field is on the original payload
object: https://github.com/parse-community/node-apn/blob/master/test/notification/index.js#L99.
In the documentation: https://github.com/parse-community/node-apn/blob/master/doc/notification.markdown#payload, the docs only mention that the aps
property will be overridden on the payload
object if aps
was set on the object.
Is this the correct intended behavior? If so, can you please share why?
Since 5.2.3, node-apn has been producing slightly wrong APS payloads, renaming events
instead of event
in the live activity push notifications.
Additionally, there wasn't any support for dismissal-date
which is used when the event
type is end
.
cc: @dplewis
Hi,
I can't seem to find the apns-id in the response (only contains device, status and response). I need the apns-id (provided along with the other apns values) to identify the original notification for failed tokens. Any ideas ?
I am following the doc to provide the proxy option when creating the APN provider, and I am using Typescript. code sample: https://www.npmjs.com/package/@parse/node-apn#connecting-through-an-http-proxy
but the TS compiler return an error when checking the types
error TS2345: Argument of type '{ token: { key: any; keyId: any; teamId: any; }; proxy: { host: any; port: number; }; production: false; }' is not assignable to parameter of type 'ProviderOptions'.
Object literal may only specify known properties, and 'proxy' does not exist in type 'ProviderOptions'.
I checked the index.d.ts, and find the proxy option is missing.
Hello, I have generated the token for push notifications at Keys section (https://developer.apple.com/account/resources/authkeys/list), enabled Apple Push Notifications service (APNs)
there, but when using the generated key (AuthKey_XXXYYYZZZ.p8
), I get an error Uncaught VError: Failed to generate token: secretOrPrivateKey must be an asymmetric key when using ES256
from lib/credentials/token/prepare.js:41:13
.
I have found that the cause probably is that Apple's generated key is a symmetrical one. Is there a way to convert it to an asymmetrical one, or generate the one that will be accepted?
Node version: v14.15.5
OS: Ubuntu
Lib version: 4.0.0
I get the following error when sending a push (running tail -f /var/log/syslog
):
Feb 14 22:33:36 myappnamehere-parse parse-server[105441]: /home/myappnamehere/prod/node_modules/parse-server/lib/ParseServer.js:237
Feb 14 22:33:36 myappnamehere-parse parse-server[105441]: throw err;
Feb 14 22:33:36 myappnamehere-parse parse-server[105441]: ^
Feb 14 22:33:36 myappnamehere-parse parse-server[105441]: TypeError: Cannot read property 'ping' of undefined
Feb 14 22:33:36 myappnamehere-parse parse-server[105441]: at ClientHttp2Session.ping (internal/http2/core.js:786:26)
Feb 14 22:33:36 myappnamehere-parse parse-server[105441]: at Timeout.Client.healthCheckInterval.setInterval [as _onTimeout] (/home/myappnamehere/prod/node_modules/@parse/node-apn/lib/client.js:29:22)
Feb 14 22:33:36 myappnamehere-parse parse-server[105441]: at ontimeout (timers.js:482:11)
Feb 14 22:33:36 myappnamehere-parse parse-server[105441]: at Timer.unrefdHandle (timers.js:595:5)
Feb 14 22:33:36 myappnamehere-parse systemd[1]: parse-server.service: Main process exited, code=exited, status=7/NOTRUNNING
Feb 14 22:33:36 myappnamehere-parse systemd[1]: parse-server.service: Failed with result 'exit-code'.
Feb 14 22:33:39 myappnamehere-parse systemd[1]: parse-server.service: Service hold-off time over, scheduling restart.
Feb 14 22:33:39 myappnamehere-parse systemd[1]: parse-server.service: Scheduled restart job, restart counter is at 2.
Feb 14 22:33:39 myappnamehere-parse systemd[1]: Stopped Parse Server.
In the parse dashboard, I see the push(es) stuck in a "SENDING" state.
Any ideas?
Thanks!
This code causes resource leak and don't close the TLS socket
const apn = require('../');
let i = 0;
const pushToken = ''
function send(provider, token) {
const note = new apn.Notification();
note.alert = `Hey hello, I just sent my first Push Notification`;
// The topic is usually the bundle identifier of your application.
note.topic = '<my-topic>';
console.log(`Sending: ${note.compile()} to`);
return provider.send(note, [token]).then(result => {
console.log('sent:', result.sent.length);
console.log('failed:', result.failed.length);
console.log(result.failed);
});
}
async function run() {
const users = [
{ name: 'Wendy', devices: [pushToken] },
];
const service = new apn.Provider({
// ...
});
Promise.all(
users.map(user => {
try {
return send(service, pushToken);
} finally {
return service.shutdown();
}
}),
)
.finally(() => {
printActiveHandles();
if (i++ < 10) {
run();
} else {
setInterval(() => {
printActiveHandles()
}, 1000)
}
});
}
function printActiveHandles() {
const data = process._getActiveHandles();
const formatted = data.map(item => item.constructor.name);
console.log(`Got ${formatted.length} active handles`, formatted);
}
run();
this will log in the end:
Got 13 active handles [
'WriteStream', 'WriteStream',
'TLSSocket', 'TLSSocket',
'TLSSocket', 'TLSSocket',
'TLSSocket', 'TLSSocket',
'TLSSocket', 'TLSSocket',
'TLSSocket', 'TLSSocket',
'TLSSocket'
]
(after releasing existing code)
node-apn is using a minimum of node 8 because that's required for the http2
module to work at all.
Not sure if this is practical for the parse organization, because https://github.com/parse-community/parse-server/blob/master/package.json still supports node 8
For my own use case of @parse/node-apn
, I'm using node 14 because of concerns about potential bugs/crashes in node 10, and the fact that they wouldn't get fixed in node 10 if discovered.
It may be possible to maintain two release lines - add any refactorings to the newest major version, but backport bug fixes, APNs API functionality, and easy improvements to the older major version for node 8+
It seems that something changed in Node v15 that makes http2 choke if a null pfx
key is set in the options object. So if you're using node-apn with a cert/key pem, it will throw an error Unable to load PFX certificate
because node-apn is setting pfx: null
in the options object.
I've circumvented this for now by deleting the pfx
key after the provider is instantiated: delete _apnsProvider.client.config.pfx
.
Currently the docs state that a topic
must be specified for a notification, but this isn't always the case. From the apple docs:
If you omit this request header and your APNs certificate does not specify multiple topics, the APNs server uses the certificate’s Subject as the default topic.
It seems like many connection timeouts and socket timeout customizations were taken out, and if there are networking issues, I'm concerned that requests to send() could hang forever (until the server ran out of memory?).
https://nodejs.org/api/http2.html#http2_http2_connect_authority_options_listener mentions options are passed to net.connect.
https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback (That doesn't look like the correct thing - I probably want the timeout to apply to requests instead)
Similar to node-apn#665
Mentioned in #23
https://nodejs.org/api/http2.html#http2_http2stream_settimeout_msecs_callback may be what I want added to ensure that the - there's examples in the documentation. Instead of NGHTTP2_CANCEL, I may want to close the client and destroy it asynchronously if requests hang for too long.
I'm assuming that each request calling req.setTimeout is its own timeout - otherwise it could get extended indefinitely
const http2 = require('http2');
const client = http2.connect('http://example.org:8000');
const { NGHTTP2_CANCEL } = http2.constants;
const req = client.request({ ':path': '/' });
// Cancel the stream if there's no activity after 5 seconds
// Instead of NGHTTP2_CANCEL, I want to close the client and destroy it asynchronously if requests hang for too long.
// Not sure what new errors that would cause this to need to handle.
// This should also use the logger to indicate that node is cancelling the stream because it took too long.
// 5 seconds may be too low for a default for a wide variety of use cases - consider using a higher timeout and making this configurable
req.setTimeout(5000, () => req.close(NGHTTP2_CANCEL));
Hi,
I am using Firebase Functions and I have stored the keys into the Environment configurations, because that's the safest place, instead of putting it into a file.
My question is how can I build an options token by directly passing the key, rather than giving a filepath?
Currently, node-apn emits debug logs such as apn Ping response after 11.645432 ms
.
This is ambiguous if more than one provider/client instances are created, e.g. when pushing to more than one app, or if refreshing credentials and creating a new Provider (exceedingly unlikely).
It may be useful to have a prefix that could be added to the passed in options to disambiguate them to see when something went wrong in a given client, e.g. here, it could be inferred that first-app stopped responding to pings
apn first-app: Ping response after 11 ms
apn second-app: Ping response after 12 ms
apn second-app: Ping response after 12 ms
apn second-app: Ping response after 12 ms
Low priority because reliability will hopefully be improved in the next release
index.d.ts:119
setLogger(logger: (string) => void, errorLogger?: (string) => void): Promise;
build error
Thanks for this great lib.
The detailed apn.Notification
documentation refers to the Apple payload documentation at https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html
This link is outdated, the modern docu can be found at https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification
In particular Table 2 is important, as it shows a set of new keys which is not present in your Convenience Setters.
Among them the subtitle and it's localised variants; subtitle-loc-key
and subtitle-loc-args
.
Would it be possible to add these and other missing ones and update your documentation?
http2.connect creates a single encrypted TCP socket. This may have limited bandwidth if there is a bottleneck in APNs, or may be more prone to some requests (99.99% percentile) taking much longer than others (e.g. 5+ seconds). If there is a dropped packet, more data would need to be retransmitted.
The original node-apn had support for HTTP proxy. This feature was apparently lost with the migration to native HTTP2 module (even if it's this mentioned in the README). It would be great if it could be added again.
I see no activity on the PRs, outdated libraries used by the code.
Hello,
one of our users reported that your version of node-forge
has some security issues (appfeel/node-pushnotifications#172)
This is the relevant Github security advisory: GHSA-2r2c-g63r-vccr
Could you look into updating the dependency on your end?
Thank you!
Best regards
Alex
It should be possible to start a server using http2 and use that to test the http2 protocol usage (e.g. edge cases with timeouts or a server getting destroyed)
E.g. https://github.com/nodejs/node/blob/master/test/parallel/test-http2-timeouts.js - the higher level api can probably be used instead
The client tests were commented out after this was refactored to use require('http2')
With iOS 15, a new notification type was added, Location Push Service Notifications Apple Docs | Setting Up A Remote Notification.
I believe a change is simply needed here index.d.ts, to simply add the text 'location'
.
Hey,
I was wondering if it's possible to set custom headers so we can try things like silent notifications? Apple says you need to pass a few key value pairs in the header to achieve that.
I am looking to set the apns-priority, apns-push-type & content-availability.
How can you send custom key / value pairs in the header with each request?
I copied the key from the .p8 file into my firebase config functions.config().apple.apn.key
. Is it possible to put the stringified key into the buffer to do something like this?
var options = {
token: {
key: Buffer.from(functions.config().apple.apn.key),
keyId: "key-id",
teamId: "developer-team-id"
},
production: false
};
var apnProvider = new apn.Provider(options);
Can't for the life of me figure out what I am doing wrong when setting up my Provider.
I am setting cert
& key
and I get this error. Please help 😢
Request ended with status 413 and responseData: {"reason":"PayloadTooLarge "}
- For regular remote notifications, the maximum size is 4KB (4096 bytes)
- For Voice over Internet Protocol (VoIP) notifications, the maximum size is 5KB (5120 bytes)
For example, add a default of 4096 bytes, and allow it to be overridden to a larger positive integer for VoIP or to account for future changes to APNs limits
Buffer.from(string)
can be used to convert the raw payload to the bytes to send, and buffer.length gets the length in bytes (instead of codepoints)If, for example, a client were to attempt to send a JSON payload that was 1 megabyte in size due to failing to truncate part of the input, it would be useful to prevent something that would definitely fail from being sent to APNs, especially if it blocked other requests to APNs or APNs server closes the connection (haven't checked if they currently do that).
(lib/provider.js is what does the final JSON.stringify)
Dear folks,
From March 15th, all iOS devices using our App have stopped receiving push notifications. When I checked the server logs, I see the below set of errors
Any idea or help?
Best Regards,
Sami
Please read carefully before closing. I'm struggling to resolve notifications for more than a week and still it's half way resolved.
Here is the provider config:
const apn = require('@parse/node-apn'); // version: "@parse/node-apn": "^5.1.3"
const iosOptions = {
token: {
key: path.resolve('./lib/AuthK*********.p8'),
keyId: '*********',
teamId: '*******'
},
production: true
};
const apnProvider = new apn.Provider(iosOptions);
const apnNotification = new apn.Notification();
apnNotification.sound = 'default';
apnNotification.title = data.title;
apnNotification.body = data.message;
apnNotification.aps.threadId = threadId;
apnNotification.topic = topic;
apnNotification.payload = payload;
apnNotification.pushType = 'alert';
apnNotification.expiry = Math.floor(Date.now() / 1000) + 3600;
apnProvider.send(apnNotification, token)
Is there anything wrong with the config?
Error message: reason: 'TopicDisallowed'
PS: I dynamically change provider options to send notifications from multiple team IDs. Is there anything to do with provider.shutdown()? Because I'm not closing this.
As said, it suddenly starts throwing the error, not always. Please help if someone knows the solution.
Some other clients disconnect for that reason, e.g. https://github.com/hisco/http2-client/blob/12a9e6fa6701a46e92e9b7adf395ce646b2a26b4/lib/request.js#L302-L318
session.on('frameError')
listens for a frame error not associated with any stream. Because this shouldn't happen, it's probably a sign of a problem with the client or server that should result in a reconnection.
Currently, @parse/node-apn
just debug logs it.
Related to #67
This contains some useful features in 4.0.0...master
On March 29, 2021, token and certificate-based HTTP/2 connections to the Apple Push Notification service must incorporate the new root certificate (AAACertificateServices 5/12/2020) which replaces the old GeoTrust Global CA root certificate. To ensure a seamless transition and to avoid push notification delivery failures, verify that both the old and new root certificates for the HTTP/2 interface are included in the Trust Store of each of your notification servers before March 29.
Will this be updated in the package?
Recently I am getting this error after sending about 11k push messages of 22k. The app was restarted and the behavior is the same.
VError: apn write timeout
2020-12-11 14:44 +00:00: at ClientHttp2Stream.<anonymous> (/node_modules/@parse/node-apn/lib/clie
nt.js:207:34)
at Object.onceWrapper (events.js:420:28)
at ClientHttp2Stream.emit (events.js:314:20)
at callTimeout (internal/http2/core.js:2181:8)
at ClientHttp2Stream._onTimeout (internal/http2/core.js:1882:5)
at listOnTimeout (internal/timers.js:554:17)
at processTimers (internal/timers.js:497:7) {
jse_shortmsg: 'apn write timeout',
jse_info: {}
}
It seems the push messages are still processed by Apple.
A switch to typescript may make sense in a major version
index.d.ts may get out of sync with the implementation. It may be easier to write everything in typescript and add a publish hook to convert code to typescript
(https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/package.json https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#including-declarations-in-your-npm-package https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/tsconfig.json)
(the publish hook would trigger a typescript build to dist/ or a subdirectory)
Alternately, with --checkJs, jsdoc can be type checked in CI
Also, class syntax can be used in node 6+ - the upstream code was supporting node 4+ and declared function Client
instead of class Client
https://github.com/parse-community/node-apn/blob/master/lib/client.js
What are the maintainer's thoughts on those ideas? Would you accept PRs?
It was done in official node-apn. It would be nice to also apply here.
node-apn@ac0e163#diff-97dd2011fdf4204ec3cc04e1adf3de602f18e6e901ccf32330bdf2ff7f9bf8e7
We have consistently been getting this error on about 1 out of 100 notifications we sent. Any idea how we can fix this?
apn write failed: New streams cannot be created after receiving a GOAWAY
I have configured the options using an AuthKey but they lib still tries to load the cert.pem file.
// apn.options.js
export const ApnOptions = {
token: {
key: "AuthKey_xxx.p8",
keyId: "xxx",
teamId: "xxx",
},
production: process.env.NODE_ENV === "production",
};
// push.js
import { ApnOptions } from "./apn.options";
const provider = new apn.Provider(ApnOptions);
Throws the following error:
Error: ENOENT: no such file or directory, open 'cert.pem'
at Object.openSync (fs.js:476:3)
at Object.readFileSync (fs.js:377:35)
at resolveCredential (/usr/srv/app/node_modules/@parse/node-apn/lib/credentials/resolve.js:16:15)
at loadCredentials (/usr/srv/app/node_modules/@parse/node-apn/lib/credentials/certificate/load.js:12:16)
at loadAndValidate (/usr/srv/app/node_modules/@parse/node-apn/lib/credentials/certificate/prepare.js:11:20)
at config (/usr/srv/app/node_modules/@parse/node-apn/lib/config.js:50:22)
at new Client (/usr/srv/app/node_modules/@parse/node-apn/lib/client.js:26:19)
at new Provider (/usr/srv/app/node_modules/@parse/node-apn/lib/provider.js:12:19)
at new PushRemindersJob (/usr/srv/app/src/cron/jobs/push.reminders.job.js:27:21)
at Task._nodeCron.default.schedule.scheduled [as execution] (/usr/srv/app/src/cron/push.cron.js:13:15) {
errno: -2,
syscall: 'open',
code: 'ENOENT',
path: 'cert.pem'
Am I missing something?
The HTTP/2-based Apple Push Notification service (APNs) provider API lets you take advantage of great features, such as authentication with a JSON Web Token, improved error messaging, and per-notification feedback. If you send push notifications with the legacy binary protocol, we strongly recommend upgrading to the APNs provider API.
To give you additional time to prepare, the deadline to upgrade to the APNs provider API has been extended to March 31, 2021. APNs will no longer support the legacy binary protocol after this date.
Does it have any impact on the node-apn package?
Hi, I'm having this issue randomly when I try to send a notification. Sometimes works, and sometimes I have this error. Anyone know that could be happening?
apn error: Request error: Error [ERR_HTTP2_STREAM_CANCEL]: The pending stream has been canceled (caused by: Client network socket disconnected before secure TLS connection was established)
apn error: Session error: Error: Client network socket disconnected before secure TLS connection was established
apn error: Session closed
stream ended unexpectedly with status null and empty body
I'm using the version 4.1.1
and I tried upgrading to the 5.0.0
, but the issue continues.
I catched this errors adding my custom logger.
Logger:
const provider = new apn.Provider(config.apns);
const infoLogger = provider.client.logger;
const errorLogger = (message) => { console.log(`apn error: ${message}`); }; // logger is declared elsewhere
errorLogger.enabled = true; // required to emulate npm debug module's interface
provider.client.setLogger(infoLogger, errorLogger);
I just upgraded to the APNS Provider API from Legacy API, and I am sending the Push Notification from my Provider Server to an apple device. The node-apn
Provider API gives a response like this:
0|app | [iOS] Push Notification Transmitted.
0|app | {
0|app | "sent": [
0|app | {
0|app | "device": "c5d152f295a7c735c1d8ba837ac99f2caa86eb6e004e29b7a9455db25fd0f2bc"
0|app | }
0|app | ],
0|app | "failed": []
0|app | }
But the device is not showing the push notification that was just sent to it. Is it APNS issue or am I missing something in the configuration of the Provider Server?
P.S. This functionality works with the older Legacy API, but the problem starts to occur when I update the Provider Server code to use the new Provider API.
I have a .pem file and password.
How can i use these for VOIP?
When Provider.shutdown()
is called with a callback, that callback is not passed through to the client.
See the source:
Provider.prototype.shutdown = function shutdown() {
this.client.shutdown();
};
This is contrary to what is specified in the TypeScript definition.
#66 was merged a while ago but no release was created.
.github/workflows/release.yml is using node 10.14, and the minimum node version package.json is 12, but it seems unrelated - instead, the issue is just that no GitHub release is created?
Are there any other planned changes for the major release?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.