import KvConst from '../const/kv-const'; import setting from '../entity/setting'; import orm from '../entity/orm'; import {verifyRecordType} from '../const/entity-const'; import fileUtils from '../utils/file-utils'; import r2Service from './r2-service'; import constant from '../const/constant'; import BizError from '../error/biz-error'; import {t} from '../i18n/i18n' import verifyRecordService from './verify-record-service'; import userContext from '../security/user-context'; const settingService = { async refresh(c) { const settingRow = await orm(c).select().from(setting).get(); settingRow.resendTokens = JSON.parse(settingRow.resendTokens); c.set('setting', settingRow); await c.env.kv.put(KvConst.SETTING, JSON.stringify(settingRow)); }, async query(c) { if (c.get?.('setting')) { return c.get('setting') } const setting = await c.env.kv.get(KvConst.SETTING, { type: 'json' }); if (!setting) { throw new BizError('数据库未初始化 Database not initialized.'); } let domainList = c.env.domain; if (typeof domainList === 'string') { try { domainList = JSON.parse(domainList) } catch (error) { throw new BizError(t('notJsonDomain')); } } if (!c.env.domain) { throw new BizError(t('noDomainVariable')); } domainList = domainList.map(item => '@' + item); setting.domainList = domainList; let linuxdoSwitch = c.env.linuxdo_switch; let projectLink = c.env.project_link; if (typeof linuxdoSwitch === 'string' && linuxdoSwitch === 'true') { linuxdoSwitch = true } else if (linuxdoSwitch === true) { linuxdoSwitch = true } else { linuxdoSwitch = false } if (typeof projectLink === 'string' && projectLink === 'false') { projectLink = false } else if (projectLink === false) { projectLink = false } else { projectLink = true } setting.projectLink = projectLink; setting.linuxdoClientId = c.env.linuxdo_client_id; setting.linuxdoCallbackUrl = c.env.linuxdo_callback_url; setting.linuxdoSwitch = linuxdoSwitch; setting.emailPrefixFilter = setting.emailPrefixFilter.split(",").filter(Boolean); c.set?.('setting', setting); return setting; }, async get(c, showSiteKey = false) { const [settingRow, recordList] = await Promise.all([ await this.query(c), verifyRecordService.selectListByIP(c) ]); if (!showSiteKey) { settingRow.siteKey = settingRow.siteKey ? `${settingRow.siteKey.slice(0, 6)}******` : null; } settingRow.secretKey = settingRow.secretKey ? `${settingRow.secretKey.slice(0, 6)}******` : null; Object.keys(settingRow.resendTokens).forEach(key => { settingRow.resendTokens[key] = `${settingRow.resendTokens[key].slice(0, 12)}******`; }); settingRow.s3AccessKey = settingRow.s3AccessKey ? `${settingRow.s3AccessKey.slice(0, 12)}******` : null; settingRow.s3SecretKey = settingRow.s3SecretKey ? `${settingRow.s3SecretKey.slice(0, 12)}******` : null; settingRow.hasR2 = !!c.env.r2 settingRow.hasCfEmail = !!c.env.email let regVerifyOpen = false let addVerifyOpen = false recordList.forEach(row => { if (row.type === verifyRecordType.REG) { regVerifyOpen = row.count >= settingRow.regVerifyCount } if (row.type === verifyRecordType.ADD) { addVerifyOpen = row.count >= settingRow.addVerifyCount } }) settingRow.regVerifyOpen = regVerifyOpen settingRow.addVerifyOpen = addVerifyOpen settingRow.storageType = await r2Service.storageType(c); return settingRow; }, async set(c, params) { const settingData = await this.query(c); let resendTokens = { ...settingData.resendTokens, ...params.resendTokens }; Object.keys(resendTokens).forEach(domain => { if (!resendTokens[domain]) delete resendTokens[domain]; }); if (Array.isArray(params.emailPrefixFilter)) { params.emailPrefixFilter = params.emailPrefixFilter + ''; } if (Array.isArray(params.aiCodeFilter)) { params.aiCodeFilter = params.aiCodeFilter + ''; } if (params.loginDarkenFactor !== undefined) { const factor = Number(params.loginDarkenFactor); params.loginDarkenFactor = Number.isNaN(factor) ? 0 : Math.min(1, Math.max(0, factor)); } params.resendTokens = JSON.stringify(resendTokens); await orm(c).update(setting).set({ ...params }).returning().get(); await this.refresh(c); }, async deleteBackground(c) { const { background } = await this.query(c); if (!background) return if (background.startsWith('http')) { await orm(c).update(setting).set({ background: '' }).run(); await this.refresh(c) return; } if (background) { await r2Service.delete(c,background) await orm(c).update(setting).set({ background: '' }).run(); await this.refresh(c) } }, async setBackground(c, params) { let { background } = params await this.deleteBackground(c); if (background && !background.startsWith('http')) { const file = fileUtils.base64ToFile(background) const arrayBuffer = await file.arrayBuffer(); background = constant.BACKGROUND_PREFIX + await fileUtils.getBuffHash(arrayBuffer) + fileUtils.getExtFileName(file.name); await r2Service.putObj(c, background, arrayBuffer, { contentType: file.type, cacheControl: `public, max-age=31536000, immutable`, contentDisposition: `inline; filename="${file.name}"` }); } await orm(c).update(setting).set({ background }).run(); await this.refresh(c); return background; }, async setBlacklist(c, params) { const { blackSubject, blackContent, blackFrom } = params await orm(c).update(setting).set({ blackSubject, blackContent, blackFrom }).run(); await this.refresh(c); return this.get(c); }, async websiteConfig(c) { const settingRow = await this.get(c, true); const token = await userContext.getToken(c); return { register: settingRow.register, title: settingRow.title, manyEmail: settingRow.manyEmail, addEmail: settingRow.addEmail, autoRefresh: settingRow.autoRefresh, addEmailVerify: settingRow.addEmailVerify, registerVerify: settingRow.registerVerify, send: settingRow.send, r2Domain: settingRow.r2Domain, siteKey: settingRow.siteKey, background: settingRow.background, loginOpacity: settingRow.loginOpacity, loginDarkenFactor: settingRow.loginDarkenFactor, domainList: settingRow.loginDomain === 1 && !token ? [] : settingRow.domainList, regKey: settingRow.regKey, regVerifyOpen: settingRow.regVerifyOpen, addVerifyOpen: settingRow.addVerifyOpen, noticeTitle: settingRow.noticeTitle, noticeContent: settingRow.noticeContent, noticeType: settingRow.noticeType, noticeDuration: settingRow.noticeDuration, noticePosition: settingRow.noticePosition, noticeWidth: settingRow.noticeWidth, noticeOffset: settingRow.noticeOffset, notice: settingRow.notice, loginDomain: settingRow.loginDomain, linuxdoClientId: settingRow.linuxdoClientId, linuxdoCallbackUrl: settingRow.linuxdoCallbackUrl, linuxdoSwitch: settingRow.linuxdoSwitch, minEmailPrefix: settingRow.minEmailPrefix, projectLink: settingRow.projectLink }; }, }; export default settingService;