verifymail.io のレスポンスをキャッシュする (MisskeyIO#424)

This commit is contained in:
riku6460 2024-02-09 20:54:13 +09:00 committed by GitHub
parent 253fc4591d
commit 258a17cb64
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -7,6 +7,7 @@ import { URLSearchParams } from 'node:url';
import * as nodemailer from 'nodemailer'; import * as nodemailer from 'nodemailer';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { validate as validateEmail } from 'deep-email-validator'; import { validate as validateEmail } from 'deep-email-validator';
import Redis from 'ioredis';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { UtilityService } from '@/core/UtilityService.js'; import { UtilityService } from '@/core/UtilityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -16,15 +17,24 @@ import type { UserProfilesRepository } from '@/models/_.js';
import { LoggerService } from '@/core/LoggerService.js'; import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { HttpRequestService } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { RedisKVCache } from '@/misc/cache.js';
@Injectable() @Injectable()
export class EmailService { export class EmailService {
private logger: Logger; private logger: Logger;
private verifymailResponseCache: RedisKVCache<{
valid: boolean,
reason?: string | null,
}>;
constructor( constructor(
@Inject(DI.config) @Inject(DI.config)
private config: Config, private config: Config,
@Inject(DI.redis)
private redisClient: Redis.Redis,
@Inject(DI.userProfilesRepository) @Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository, private userProfilesRepository: UserProfilesRepository,
@ -34,6 +44,16 @@ export class EmailService {
private httpRequestService: HttpRequestService, private httpRequestService: HttpRequestService,
) { ) {
this.logger = this.loggerService.getLogger('email'); this.logger = this.loggerService.getLogger('email');
this.verifymailResponseCache = new RedisKVCache<{
valid: boolean,
reason?: string | null,
}>(this.redisClient, 'verifymailResponse', {
lifetime: 1000 * 60 * 60 * 24 * 7, // 7d
memoryCacheLifetime: 1000 * 60 * 60 * 24 * 7, // 7d
fetcher: (key) => this.verifyMail(key),
toRedisConverter: (value) => JSON.stringify(value),
fromRedisConverter: (value) => JSON.parse(value),
});
} }
@bindThis @bindThis
@ -190,7 +210,8 @@ export class EmailService {
}); });
if (validated.valid && meta.enableVerifymailApi && meta.verifymailAuthKey != null) { if (validated.valid && meta.enableVerifymailApi && meta.verifymailAuthKey != null) {
validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey); const domain = emailAddress.split('@')[1];
validated = await this.verifymailResponseCache.fetch(domain);
} }
if (validated.valid && meta.enableTruemailApi && meta.truemailInstance && meta.truemailAuthKey != null) { if (validated.valid && meta.enableTruemailApi && meta.truemailInstance && meta.truemailAuthKey != null) {
@ -230,11 +251,14 @@ export class EmailService {
}; };
} }
private async verifyMail(emailAddress: string, verifymailAuthKey: string): Promise<{ private async verifyMail(domain: string): Promise<{
valid: boolean; valid: boolean;
reason: 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | null; reason: 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | null;
}> { }> {
const endpoint = 'https://verifymail.io/api/' + emailAddress + '?key=' + verifymailAuthKey; const meta = await this.metaService.fetch();
if (meta.verifymailAuthKey == null) throw new Error('verifymailAuthKey is not set');
const endpoint = 'https://verifymail.io/api/' + domain + '?key=' + meta.verifymailAuthKey;
const res = await this.httpRequestService.send(endpoint, { const res = await this.httpRequestService.send(endpoint, {
method: 'GET', method: 'GET',
headers: { headers: {