mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-29 13:05:08 +02:00
118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
//
|
|
// Copyright © 2023 Hardcore Engineering Inc.
|
|
//
|
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License. You may
|
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
//
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import type { Ref } from '@hcengineering/core'
|
|
import { PushSubscription, type PushData } from '@hcengineering/notification'
|
|
import type { Request, Response } from 'express'
|
|
import webpush, { WebPushError } from 'web-push'
|
|
import config from './config'
|
|
import { createServer, listen } from './server'
|
|
import { Endpoint } from './types'
|
|
|
|
const errorMessages = ['expired', 'Unregistered', 'No such subscription']
|
|
async function sendPushToSubscription (
|
|
subscriptions: PushSubscription[],
|
|
data: PushData
|
|
): Promise<Ref<PushSubscription>[]> {
|
|
const result: Ref<PushSubscription>[] = []
|
|
for (const subscription of subscriptions) {
|
|
try {
|
|
await webpush.sendNotification(subscription, JSON.stringify(data))
|
|
} catch (err: any) {
|
|
if (err instanceof WebPushError) {
|
|
if (errorMessages.some((p) => JSON.stringify(err.body).includes(p))) {
|
|
result.push(subscription._id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
export const main = async (): Promise<void> => {
|
|
console.log('Notification service has been started')
|
|
let webpushInitDone = false
|
|
|
|
if (config.PushPublicKey !== undefined && config.PushPrivateKey !== undefined) {
|
|
try {
|
|
const subj = config.PushSubject ?? 'mailto:hey@huly.io'
|
|
console.log('Setting VAPID details', subj, config.PushPublicKey.length, config.PushPrivateKey.length)
|
|
webpush.setVapidDetails(config.PushSubject ?? 'mailto:hey@huly.io', config.PushPublicKey, config.PushPrivateKey)
|
|
webpushInitDone = true
|
|
} catch (err: any) {
|
|
console.error(err)
|
|
}
|
|
}
|
|
|
|
const checkAuth = (req: Request<any>, res: Response<any>): boolean => {
|
|
if (config.AuthToken !== undefined) {
|
|
// We need to verify authorization
|
|
const authorization = req.headers.authorization ?? ''
|
|
const token = authorization.replace('Bearer ', '')
|
|
if (token !== config.AuthToken) {
|
|
res.status(401).send({ err: 'Invalid auth token' })
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
const endpoints: Endpoint[] = [
|
|
{
|
|
endpoint: '/web-push',
|
|
type: 'post',
|
|
handler: async (req, res) => {
|
|
if (!checkAuth(req, res)) {
|
|
return
|
|
}
|
|
const data: PushData | undefined = req.body?.data
|
|
if (data === undefined) {
|
|
res.status(400).send({ err: "'data' is missing" })
|
|
return
|
|
}
|
|
const subscriptions: PushSubscription[] | undefined = req.body?.subscriptions
|
|
if (subscriptions === undefined) {
|
|
res.status(400).send({ err: "'subscriptions' is missing" })
|
|
return
|
|
}
|
|
if (!webpushInitDone) {
|
|
res.json({ result: [] }).end()
|
|
return
|
|
}
|
|
|
|
const result = await sendPushToSubscription(subscriptions, data)
|
|
res.json({ result }).end()
|
|
}
|
|
}
|
|
]
|
|
|
|
const server = listen(createServer(endpoints), config.Port)
|
|
|
|
const shutdown = (): void => {
|
|
server.close(() => {
|
|
process.exit()
|
|
})
|
|
}
|
|
|
|
process.on('SIGINT', shutdown)
|
|
process.on('SIGTERM', shutdown)
|
|
process.on('uncaughtException', (e) => {
|
|
console.error(e)
|
|
})
|
|
process.on('unhandledRejection', (e) => {
|
|
console.error(e)
|
|
})
|
|
}
|