mirror of
				https://github.com/nodemailer/wildduck.git
				synced 2025-11-04 12:07:14 +08:00 
			
		
		
		
	updated autiding
This commit is contained in:
		
							parent
							
								
									7abe3215a4
								
							
						
					
					
						commit
						4a194b6502
					
				
					 8 changed files with 96 additions and 28 deletions
				
			
		
							
								
								
									
										14
									
								
								indexes.yaml
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								indexes.yaml
									
										
									
									
									
								
							| 
						 | 
					@ -561,6 +561,20 @@ indexes:
 | 
				
			||||||
              locked: 1
 | 
					              locked: 1
 | 
				
			||||||
              lockedUntil: 1
 | 
					              lockedUntil: 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - collection: audits
 | 
				
			||||||
 | 
					      index:
 | 
				
			||||||
 | 
					          name: user_expire_time
 | 
				
			||||||
 | 
					          key:
 | 
				
			||||||
 | 
					              user: 1
 | 
				
			||||||
 | 
					              expires: 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - collection: audits
 | 
				
			||||||
 | 
					      index:
 | 
				
			||||||
 | 
					          name: expire_time
 | 
				
			||||||
 | 
					          key:
 | 
				
			||||||
 | 
					              expires: 1
 | 
				
			||||||
 | 
					              deleted: 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - collection: audit.files
 | 
					    - collection: audit.files
 | 
				
			||||||
      type: gridfs # index applies to gridfs database
 | 
					      type: gridfs # index applies to gridfs database
 | 
				
			||||||
      index:
 | 
					      index:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,12 +36,18 @@ class AuditHandler {
 | 
				
			||||||
            start: options.start, // Date or null
 | 
					            start: options.start, // Date or null
 | 
				
			||||||
            end: options.end, // Date or null
 | 
					            end: options.end, // Date or null
 | 
				
			||||||
            expires: options.expires, // Date
 | 
					            expires: options.expires, // Date
 | 
				
			||||||
 | 
					            deleted: false, // Boolean
 | 
				
			||||||
 | 
					            notes: options.nodes, // String
 | 
				
			||||||
 | 
					            meta: options.meta || {}, // Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            import: {
 | 
					            import: {
 | 
				
			||||||
                status: 'queued',
 | 
					                status: 'queued',
 | 
				
			||||||
                failed: 0,
 | 
					                failed: 0,
 | 
				
			||||||
                copied: 0
 | 
					                copied: 0
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            audited: 0,
 | 
				
			||||||
 | 
					            lastAuditedMessage: null
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let r;
 | 
					        let r;
 | 
				
			||||||
| 
						 | 
					@ -96,7 +102,7 @@ class AuditHandler {
 | 
				
			||||||
     * @param {Mixed} message Either a Buffer, an Array of Buffers or a Stream
 | 
					     * @param {Mixed} message Either a Buffer, an Array of Buffers or a Stream
 | 
				
			||||||
     * @param {Object} metadata Metadata for the stored message
 | 
					     * @param {Object} metadata Metadata for the stored message
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    async store(audit, message, metadata) {
 | 
					    async store(audit, message, metadata, skipCounters) {
 | 
				
			||||||
        if (!message) {
 | 
					        if (!message) {
 | 
				
			||||||
            throw new Error('Missing message content');
 | 
					            throw new Error('Missing message content');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -111,7 +117,7 @@ class AuditHandler {
 | 
				
			||||||
        metadata.audit = metadata.audit || audit;
 | 
					        metadata.audit = metadata.audit || audit;
 | 
				
			||||||
        metadata.date = metadata.date || new Date();
 | 
					        metadata.date = metadata.date || new Date();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return new Promise((resolve, reject) => {
 | 
					        let result = await new Promise((resolve, reject) => {
 | 
				
			||||||
            let stream = this.gridstore.openUploadStreamWithId(id, null, {
 | 
					            let stream = this.gridstore.openUploadStreamWithId(id, null, {
 | 
				
			||||||
                contentType: 'message/rfc822',
 | 
					                contentType: 'message/rfc822',
 | 
				
			||||||
                metadata
 | 
					                metadata
 | 
				
			||||||
| 
						 | 
					@ -145,6 +151,12 @@ class AuditHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            message.pipe(stream);
 | 
					            message.pipe(stream);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (result && !skipCounters) {
 | 
				
			||||||
 | 
					            await this.database.collection('audits').updateOne({ _id: metadata.audit }, { $inc: { audited: 1 }, $set: { lastAuditedMessage: new Date() } });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -207,15 +219,19 @@ class AuditHandler {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        await cursor.close();
 | 
					        await cursor.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await this.database.collection('audits').deleteOne({ _id: auditData._id });
 | 
					        await this.database.collection('audits').updateOne({ _id: auditData._id }, { $set: { deleted: true, deletedTime: new Date() } });
 | 
				
			||||||
        log.info('Audit', 'Deleted expired audit %s (%s messages)', auditData._id, messages);
 | 
					        log.info('Audit', 'Deleted audit %s (%s messages)', auditData._id, messages);
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            audit: auditData._id,
 | 
				
			||||||
 | 
					            messages
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async cleanExpired() {
 | 
					    async cleanExpired() {
 | 
				
			||||||
        let expiredAudits = await this.database
 | 
					        let expiredAudits = await this.database
 | 
				
			||||||
            .collection('audits')
 | 
					            .collection('audits')
 | 
				
			||||||
            .find({
 | 
					            .find({
 | 
				
			||||||
                expires: { $lt: new Date() }
 | 
					                expires: { $lt: new Date(), deleted: false }
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .toArray();
 | 
					            .toArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -482,6 +482,29 @@ class FilterHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            filterResults.push({ delete: true });
 | 
					            filterResults.push({ delete: true });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                let audits = await this.database
 | 
				
			||||||
 | 
					                    .collection('audits')
 | 
				
			||||||
 | 
					                    .find({ user: userData._id, expires: { $gt: new Date() } })
 | 
				
			||||||
 | 
					                    .toArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let now = new Date();
 | 
				
			||||||
 | 
					                for (let auditData of audits) {
 | 
				
			||||||
 | 
					                    if ((auditData.start && auditData.start > now) || (auditData.end && auditData.end < now)) {
 | 
				
			||||||
 | 
					                        // audit not active
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    await this.auditHandler.store(auditData._id, rawchunks, {
 | 
				
			||||||
 | 
					                        date: prepared.idate || new Date(),
 | 
				
			||||||
 | 
					                        msgid: prepared.msgid,
 | 
				
			||||||
 | 
					                        header: prepared.mimeTree && prepared.mimeTree.parsedHeader,
 | 
				
			||||||
 | 
					                        ha: prepared.ha,
 | 
				
			||||||
 | 
					                        info: Object.assign({ notStored: true }, meta || {})
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } catch (err) {
 | 
				
			||||||
 | 
					                log.error('Filter', '%s AUDITFAIL from=%s to=%s error=%s', prepared.id.toString(), '<>', sender, err.message);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            return {
 | 
					            return {
 | 
				
			||||||
                response: {
 | 
					                response: {
 | 
				
			||||||
                    userData,
 | 
					                    userData,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -473,7 +473,10 @@ class MessageHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                                    let raw = options.rawchunks || options.raw;
 | 
					                                                    let raw = options.rawchunks || options.raw;
 | 
				
			||||||
                                                    let processAudits = async () => {
 | 
					                                                    let processAudits = async () => {
 | 
				
			||||||
                                                        let audits = await this.database.collection('audits').find({ user: mailboxData.user }).toArray();
 | 
					                                                        let audits = await this.database
 | 
				
			||||||
 | 
					                                                            .collection('audits')
 | 
				
			||||||
 | 
					                                                            .find({ user: mailboxData.user, expires: { $gt: new Date() } })
 | 
				
			||||||
 | 
					                                                            .toArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                                        let now = new Date();
 | 
					                                                        let now = new Date();
 | 
				
			||||||
                                                        for (let auditData of audits) {
 | 
					                                                        for (let auditData of audits) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,12 +30,7 @@ let run = async (taskData, options) => {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mailboxes = new Map(
 | 
					    let mailboxes = new Map(
 | 
				
			||||||
        (
 | 
					        (await db.database.collection('mailboxes').find({ user: taskData.user }).toArray()).map(mailboxData => [mailboxData._id.toString(), mailboxData])
 | 
				
			||||||
            await db.database
 | 
					 | 
				
			||||||
                .collection('mailboxes')
 | 
					 | 
				
			||||||
                .find({ user: taskData.user })
 | 
					 | 
				
			||||||
                .toArray()
 | 
					 | 
				
			||||||
        ).map(mailboxData => [mailboxData._id.toString(), mailboxData])
 | 
					 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let processMessage = async messageData => {
 | 
					    let processMessage = async messageData => {
 | 
				
			||||||
| 
						 | 
					@ -44,16 +39,22 @@ let run = async (taskData, options) => {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let mailboxData = messageData.mailbox ? mailboxes.get(messageData.mailbox.toString()) : false;
 | 
					        let mailboxData = messageData.mailbox ? mailboxes.get(messageData.mailbox.toString()) : false;
 | 
				
			||||||
        let auditMessage = await auditHandler.store(taskData.audit, builder.value, {
 | 
					        let auditMessage = await auditHandler.store(
 | 
				
			||||||
            date: messageData.idate,
 | 
					            taskData.audit,
 | 
				
			||||||
            msgid: messageData.msgid,
 | 
					            builder.value,
 | 
				
			||||||
            header: messageData.mimeTree && messageData.mimeTree.parsedHeader,
 | 
					            {
 | 
				
			||||||
            ha: messageData.ha,
 | 
					                date: messageData.idate,
 | 
				
			||||||
            mailbox: messageData.mailbox,
 | 
					                msgid: messageData.msgid,
 | 
				
			||||||
            mailboxPath: mailboxData ? mailboxData.path : false,
 | 
					                header: messageData.mimeTree && messageData.mimeTree.parsedHeader,
 | 
				
			||||||
            info: messageData.meta,
 | 
					                ha: messageData.ha,
 | 
				
			||||||
            draft: messageData.draft
 | 
					                mailbox: messageData.mailbox,
 | 
				
			||||||
        });
 | 
					                mailboxPath: mailboxData ? mailboxData.path : false,
 | 
				
			||||||
 | 
					                info: messageData.meta,
 | 
				
			||||||
 | 
					                draft: messageData.draft,
 | 
				
			||||||
 | 
					                imported: true
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            true
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return auditMessage;
 | 
					        return auditMessage;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					@ -98,7 +99,11 @@ let run = async (taskData, options) => {
 | 
				
			||||||
                            { _id: taskData.audit },
 | 
					                            { _id: taskData.audit },
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                $inc: {
 | 
					                                $inc: {
 | 
				
			||||||
                                    'import.copied': 1
 | 
					                                    'import.copied': 1,
 | 
				
			||||||
 | 
					                                    audited: 1
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                $set: {
 | 
				
			||||||
 | 
					                                    lastAuditedMessage: new Date()
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    "name": "wildduck",
 | 
					    "name": "wildduck",
 | 
				
			||||||
    "version": "1.26.3",
 | 
					    "version": "1.26.4",
 | 
				
			||||||
    "description": "IMAP/POP3 server built with Node.js and MongoDB",
 | 
					    "description": "IMAP/POP3 server built with Node.js and MongoDB",
 | 
				
			||||||
    "main": "server.js",
 | 
					    "main": "server.js",
 | 
				
			||||||
    "scripts": {
 | 
					    "scripts": {
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,7 @@
 | 
				
			||||||
        "he": "1.2.0",
 | 
					        "he": "1.2.0",
 | 
				
			||||||
        "html-to-text": "5.1.1",
 | 
					        "html-to-text": "5.1.1",
 | 
				
			||||||
        "humanname": "0.2.2",
 | 
					        "humanname": "0.2.2",
 | 
				
			||||||
        "iconv-lite": "0.6.0",
 | 
					        "iconv-lite": "0.6.1",
 | 
				
			||||||
        "ioredfour": "1.0.2-ioredis-03",
 | 
					        "ioredfour": "1.0.2-ioredis-03",
 | 
				
			||||||
        "ioredis": "4.17.3",
 | 
					        "ioredis": "4.17.3",
 | 
				
			||||||
        "isemail": "3.2.0",
 | 
					        "isemail": "3.2.0",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -261,7 +261,7 @@ SERVICE_NAME=$1
 | 
				
			||||||
# Ensure required files and permissions
 | 
					# Ensure required files and permissions
 | 
				
			||||||
echo "d /var/log/${SERVICE_NAME} 0750 syslog adm" > /etc/tmpfiles.d/${SERVICE_NAME}-log.conf
 | 
					echo "d /var/log/${SERVICE_NAME} 0750 syslog adm" > /etc/tmpfiles.d/${SERVICE_NAME}-log.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Redirect MongoDB log output from syslog to mongodb log file
 | 
					# Redirect MongoDB log output from syslog to service specific log file
 | 
				
			||||||
echo "if ( \$programname startswith \"$SERVICE_NAME\" ) then {
 | 
					echo "if ( \$programname startswith \"$SERVICE_NAME\" ) then {
 | 
				
			||||||
    action(type=\"omfile\" file=\"/var/log/${SERVICE_NAME}/${SERVICE_NAME}.log\")
 | 
					    action(type=\"omfile\" file=\"/var/log/${SERVICE_NAME}/${SERVICE_NAME}.log\")
 | 
				
			||||||
    stop
 | 
					    stop
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,8 +27,15 @@ echo "deb https://deb.nodesource.com/$NODEREPO $CODENAME main" > /etc/apt/source
 | 
				
			||||||
echo "deb-src https://deb.nodesource.com/$NODEREPO $CODENAME main" >> /etc/apt/sources.list.d/nodesource.list
 | 
					echo "deb-src https://deb.nodesource.com/$NODEREPO $CODENAME main" >> /etc/apt/sources.list.d/nodesource.list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# mongo keys
 | 
					# mongo keys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MONGORELEASE=$CODENAME
 | 
				
			||||||
 | 
					if [ "$MONGORELEASE" = "focal" ]; then
 | 
				
			||||||
 | 
					  # Ubuntu 20 is not yet supported (as of 2020-07-01), fallback to 18
 | 
				
			||||||
 | 
					  MONGORELEASE="bionic"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
wget -qO- https://www.mongodb.org/static/pgp/server-${MONGODB}.asc | apt-key add
 | 
					wget -qO- https://www.mongodb.org/static/pgp/server-${MONGODB}.asc | apt-key add
 | 
				
			||||||
echo "deb [ arch=amd64 ] http://repo.mongodb.org/apt/ubuntu $CODENAME/mongodb-org/$MONGODB multiverse" > /etc/apt/sources.list.d/mongodb-org.list
 | 
					echo "deb [ arch=amd64 ] http://repo.mongodb.org/apt/ubuntu $MONGORELEASE/mongodb-org/$MONGODB multiverse" > /etc/apt/sources.list.d/mongodb-org.list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# rspamd
 | 
					# rspamd
 | 
				
			||||||
wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add -
 | 
					wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add -
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue