179 lines
5.1 KiB
JavaScript
179 lines
5.1 KiB
JavaScript
const Logger = require('../../Logger')
|
|
const { areEquivalent, copyValue, isNullOrNaN } = require('../../utils')
|
|
|
|
/**
|
|
* @typedef EreaderDeviceObject
|
|
* @property {string} name
|
|
* @property {string} email
|
|
* @property {string} availabilityOption
|
|
* @property {string[]} users
|
|
*/
|
|
|
|
// REF: https://nodemailer.com/smtp/
|
|
class EmailSettings {
|
|
constructor(settings = null) {
|
|
this.id = 'email-settings'
|
|
this.host = null
|
|
this.port = 465
|
|
this.secure = true
|
|
this.rejectUnauthorized = true
|
|
this.user = null
|
|
this.pass = null
|
|
this.testAddress = null
|
|
this.fromAddress = null
|
|
|
|
/** @type {EreaderDeviceObject[]} */
|
|
this.ereaderDevices = []
|
|
|
|
if (settings) {
|
|
this.construct(settings)
|
|
}
|
|
}
|
|
|
|
construct(settings) {
|
|
this.host = settings.host
|
|
this.port = settings.port
|
|
this.secure = !!settings.secure
|
|
this.rejectUnauthorized = !!settings.rejectUnauthorized
|
|
this.user = settings.user
|
|
this.pass = settings.pass
|
|
this.testAddress = settings.testAddress
|
|
this.fromAddress = settings.fromAddress
|
|
this.ereaderDevices = settings.ereaderDevices?.map((d) => ({ ...d })) || []
|
|
|
|
// rejectUnauthorized added after v2.10.1 - defaults to true
|
|
if (settings.rejectUnauthorized === undefined) {
|
|
this.rejectUnauthorized = true
|
|
}
|
|
}
|
|
|
|
toJSON() {
|
|
return {
|
|
id: this.id,
|
|
host: this.host,
|
|
port: this.port,
|
|
secure: this.secure,
|
|
rejectUnauthorized: this.rejectUnauthorized,
|
|
user: this.user,
|
|
pass: this.pass,
|
|
testAddress: this.testAddress,
|
|
fromAddress: this.fromAddress,
|
|
ereaderDevices: this.ereaderDevices.map((d) => ({ ...d }))
|
|
}
|
|
}
|
|
|
|
update(payload) {
|
|
if (!payload) return false
|
|
|
|
if (payload.port !== undefined) {
|
|
if (isNullOrNaN(payload.port)) payload.port = 465
|
|
else payload.port = Number(payload.port)
|
|
}
|
|
if (payload.secure !== undefined) payload.secure = !!payload.secure
|
|
if (payload.rejectUnauthorized !== undefined) payload.rejectUnauthorized = !!payload.rejectUnauthorized
|
|
|
|
if (payload.ereaderDevices !== undefined && !Array.isArray(payload.ereaderDevices)) payload.ereaderDevices = undefined
|
|
|
|
if (payload.ereaderDevices?.length) {
|
|
// Validate ereader devices
|
|
payload.ereaderDevices = payload.ereaderDevices
|
|
.map((device) => {
|
|
if (!device.name || !device.email) {
|
|
Logger.error(`[EmailSettings] Update ereader device is invalid`, device)
|
|
return null
|
|
}
|
|
if (!device.availabilityOption || !['adminOrUp', 'userOrUp', 'guestOrUp', 'specificUsers'].includes(device.availabilityOption)) {
|
|
device.availabilityOption = 'adminOrUp'
|
|
}
|
|
if (device.availabilityOption === 'specificUsers' && !device.users?.length) {
|
|
device.availabilityOption = 'adminOrUp'
|
|
}
|
|
if (device.availabilityOption !== 'specificUsers' && device.users?.length) {
|
|
device.users = []
|
|
}
|
|
return device
|
|
})
|
|
.filter((d) => d)
|
|
}
|
|
|
|
let hasUpdates = false
|
|
|
|
const json = this.toJSON()
|
|
for (const key in json) {
|
|
if (key === 'id') continue
|
|
|
|
if (payload[key] !== undefined && !areEquivalent(payload[key], json[key])) {
|
|
this[key] = copyValue(payload[key])
|
|
hasUpdates = true
|
|
}
|
|
}
|
|
|
|
return hasUpdates
|
|
}
|
|
|
|
getTransportObject() {
|
|
const payload = {
|
|
host: this.host,
|
|
secure: this.secure
|
|
}
|
|
// Only set to true for port 465 (https://nodemailer.com/smtp/#tls-options)
|
|
if (this.port !== 465) {
|
|
payload.secure = false
|
|
}
|
|
if (this.port) payload.port = this.port
|
|
if (this.user && this.pass !== undefined) {
|
|
payload.auth = {
|
|
user: this.user,
|
|
pass: this.pass
|
|
}
|
|
}
|
|
// Allow self-signed certs (https://nodemailer.com/smtp/#3-allow-self-signed-certificates)
|
|
if (!this.rejectUnauthorized) {
|
|
payload.tls = {
|
|
rejectUnauthorized: false
|
|
}
|
|
}
|
|
|
|
return payload
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {EreaderDeviceObject} device
|
|
* @param {import('../../models/User')} user
|
|
* @returns {boolean}
|
|
*/
|
|
checkUserCanAccessDevice(device, user) {
|
|
let deviceAvailability = device.availabilityOption || 'adminOrUp'
|
|
if (deviceAvailability === 'adminOrUp' && user.isAdminOrUp) return true
|
|
if (deviceAvailability === 'userOrUp' && (user.isAdminOrUp || user.isUser)) return true
|
|
if (deviceAvailability === 'guestOrUp') return true
|
|
if (deviceAvailability === 'specificUsers') {
|
|
let deviceUsers = device.users || []
|
|
return deviceUsers.includes(user.id)
|
|
}
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* Get ereader devices accessible to user
|
|
*
|
|
* @param {import('../../models/User')} user
|
|
* @returns {EreaderDeviceObject[]}
|
|
*/
|
|
getEReaderDevices(user) {
|
|
return this.ereaderDevices.filter((device) => this.checkUserCanAccessDevice(device, user))
|
|
}
|
|
|
|
/**
|
|
* Get ereader device by name
|
|
*
|
|
* @param {string} deviceName
|
|
* @returns {EreaderDeviceObject}
|
|
*/
|
|
getEReaderDevice(deviceName) {
|
|
return this.ereaderDevices.find((d) => d.name === deviceName)
|
|
}
|
|
}
|
|
module.exports = EmailSettings
|