2022-09-23 13:42:06 +00:00
|
|
|
const AkismetClient = require('akismet-api').AkismetClient
|
|
|
|
|
|
|
|
let akismetClient
|
|
|
|
|
|
|
|
async function register ({
|
|
|
|
settingsManager,
|
|
|
|
peertubeHelpers,
|
|
|
|
registerSetting,
|
|
|
|
registerHook
|
|
|
|
}) {
|
|
|
|
registerSetting({
|
|
|
|
name: 'akismet-api-key',
|
|
|
|
label: 'Akismet API key',
|
|
|
|
type: 'input-password',
|
|
|
|
private: true
|
|
|
|
})
|
|
|
|
|
|
|
|
const settings = await settingsManager.getSettings([ 'akismet-api-key' ])
|
|
|
|
await updateSettings(peertubeHelpers, settings)
|
|
|
|
|
|
|
|
settingsManager.onSettingsChange(async settings => {
|
|
|
|
await updateSettings(peertubeHelpers, settings)
|
|
|
|
})
|
|
|
|
|
|
|
|
for (const hook of [
|
|
|
|
'filter:api.video-thread.create.accept.result',
|
|
|
|
'filter:api.video-comment-reply.create.accept.result'
|
|
|
|
]) {
|
|
|
|
registerHook({
|
|
|
|
target: hook,
|
|
|
|
handler: (result, params) => {
|
|
|
|
if (!akismetClient) return result
|
|
|
|
if (!result.accepted) return result
|
|
|
|
|
|
|
|
return checkLocalComment(peertubeHelpers, {
|
|
|
|
// No req in params before 5.0
|
|
|
|
ip: params.req
|
|
|
|
? params.req.ip
|
|
|
|
: '127.0.0.1',
|
|
|
|
|
|
|
|
userAgent: params.req
|
|
|
|
? params.req.get('user-agent')
|
|
|
|
: undefined,
|
|
|
|
|
|
|
|
commentType: params.parentComment
|
|
|
|
? 'reply'
|
|
|
|
: 'comment',
|
|
|
|
|
|
|
|
text: params.commentBody.text,
|
|
|
|
authorEmail: params.user.email,
|
|
|
|
author: params.user.username
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
registerHook({
|
|
|
|
target: 'filter:activity-pub.remote-video-comment.create.accept.result',
|
|
|
|
handler: (result, params) => {
|
|
|
|
if (!akismetClient) return result
|
|
|
|
if (!result.accepted) return result
|
|
|
|
|
|
|
|
return checkRemoteComment(peertubeHelpers, {
|
|
|
|
text: params.comment.text,
|
|
|
|
commentType: params.comment.originCommentId
|
|
|
|
? 'reply'
|
|
|
|
: 'comment'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2022-09-23 14:14:38 +00:00
|
|
|
|
|
|
|
registerHook({
|
|
|
|
target: 'filter:api.user.signup.allowed.result',
|
|
|
|
handler: (result, params) => {
|
|
|
|
if (!akismetClient) return result
|
|
|
|
if (!result.allowed) return result
|
|
|
|
if (!params.body) return result
|
|
|
|
|
|
|
|
return checkSignup(peertubeHelpers, {
|
|
|
|
ip: params.ip,
|
|
|
|
username: params.body.username,
|
|
|
|
email: params.body.email
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2022-09-23 13:42:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async function unregister () {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
register,
|
|
|
|
unregister
|
|
|
|
}
|
|
|
|
|
|
|
|
// ############################################################################
|
|
|
|
|
|
|
|
async function updateSettings (peertubeHelpers, settings) {
|
|
|
|
const { logger } = peertubeHelpers
|
|
|
|
|
|
|
|
apiKey = settings['akismet-api-key']
|
|
|
|
if (!apiKey) {
|
|
|
|
akismetClient = undefined
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
akismetClient = new AkismetClient({ key: settings['akismet-api-key'], blog: peertubeHelpers.config.getWebserverUrl() })
|
|
|
|
|
|
|
|
try {
|
|
|
|
const isValid = await akismetClient.verifyKey()
|
|
|
|
|
|
|
|
if (isValid) {
|
|
|
|
logger.info('Loaded valid Akismet key.')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.error('Invalid Akismet key.')
|
|
|
|
akismetClient = undefined
|
|
|
|
} catch (err) {
|
|
|
|
logger.error('Cannot reach Akismet.', { err })
|
|
|
|
akismetClient = undefined
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function checkLocalComment (peertubeHelpers, options) {
|
|
|
|
const { logger } = peertubeHelpers
|
|
|
|
|
|
|
|
for (const key of [ 'ip', 'text', 'commentType', 'author', 'authorEmail' ]) {
|
|
|
|
if (!options[key]) {
|
|
|
|
logger.error('Cannot check local comment from Akismet without ' + key)
|
2022-09-23 14:14:38 +00:00
|
|
|
return accept()
|
2022-09-23 13:42:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/chrisfosterelli/akismet-api/blob/master/docs/comments.md
|
|
|
|
const comment = {
|
|
|
|
ip: options.ip,
|
|
|
|
content: options.text,
|
|
|
|
type: options.commentType,
|
|
|
|
name: options.author,
|
|
|
|
email: options.authorEmail,
|
|
|
|
|
|
|
|
// Optional
|
|
|
|
useragent: options.userAgent
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const isSpam = await akismetClient.checkSpam(comment)
|
|
|
|
logger.info('Checking local comment from Akismet.', { comment, isSpam })
|
|
|
|
|
2022-09-23 14:14:38 +00:00
|
|
|
if (isSpam) return reject()
|
2022-09-23 13:42:06 +00:00
|
|
|
} catch (err) {
|
|
|
|
logger.error('Cannot reach Akismet.', { err, comment })
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:14:38 +00:00
|
|
|
return accept()
|
2022-09-23 13:42:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async function checkRemoteComment (peertubeHelpers, options) {
|
|
|
|
const { logger } = peertubeHelpers
|
|
|
|
|
|
|
|
for (const key of [ 'text' ]) {
|
|
|
|
if (!options[key]) {
|
|
|
|
logger.error('Cannot check local comment from Akismet without ' + key)
|
2022-09-23 14:14:38 +00:00
|
|
|
return accept()
|
2022-09-23 13:42:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/chrisfosterelli/akismet-api/blob/master/docs/comments.md
|
|
|
|
const comment = {
|
|
|
|
ip: '127.0.0.1',
|
|
|
|
content: options.text,
|
|
|
|
type: options.commentType
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const isSpam = await akismetClient.checkSpam(comment)
|
|
|
|
logger.info('Checking remote comment from Akismet.', { comment, isSpam })
|
|
|
|
|
2022-09-23 14:14:38 +00:00
|
|
|
if (isSpam) return reject()
|
2022-09-23 13:42:06 +00:00
|
|
|
} catch (err) {
|
|
|
|
logger.error('Cannot reach Akismet.', { err, comment })
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:14:38 +00:00
|
|
|
return accept()
|
|
|
|
}
|
|
|
|
|
|
|
|
async function checkSignup (peertubeHelpers, options) {
|
|
|
|
const { logger } = peertubeHelpers
|
|
|
|
|
|
|
|
for (const key of [ 'ip', 'username', 'email' ]) {
|
|
|
|
if (!options[key]) {
|
|
|
|
logger.error('Cannot check signup from Akismet without ' + key)
|
|
|
|
return allow()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/chrisfosterelli/akismet-api/blob/master/docs/comments.md
|
|
|
|
const payload = {
|
|
|
|
ip: options.ip,
|
|
|
|
type: 'signup',
|
|
|
|
name: options.username,
|
|
|
|
email: options.email,
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const isSpam = await akismetClient.checkSpam(payload)
|
|
|
|
logger.info('Checking signup from Akismet.', { payload, isSpam })
|
|
|
|
|
|
|
|
if (isSpam) return forbid()
|
|
|
|
} catch (err) {
|
|
|
|
logger.error('Cannot reach Akismet.', { err, payload })
|
|
|
|
}
|
|
|
|
|
|
|
|
return allow()
|
|
|
|
}
|
|
|
|
|
|
|
|
function accept () {
|
|
|
|
return { accepted: true }
|
|
|
|
}
|
|
|
|
|
|
|
|
function reject () {
|
|
|
|
return { accepted: false, errorMessage: 'SPAM detected from Akismet' }
|
|
|
|
}
|
|
|
|
|
|
|
|
function allow () {
|
|
|
|
return { allowed: true }
|
|
|
|
}
|
|
|
|
|
|
|
|
function forbid () {
|
|
|
|
return { allowed: false, errorMessage: 'SPAM detected from Akismet' }
|
2022-09-23 13:42:06 +00:00
|
|
|
}
|