Intercept AP Create.Note and check if contains #fedilovequiz to parse

* FediLove Quiz is a standar text-based (parsed) protocol wrapped inside the object "Note"
 that can create a Quiz inside FediLove instance so there can be an interaction between non-FediLove
 instances and FediLove instances.
* TODO: implement the response from this side, so it goes parsed as a regular response to the original "Note"
 but parsed so if the target instance is FediLove, it parses it as a quiz result and can be interpreted on any AP software
This commit is contained in:
Niko 2022-02-21 23:54:59 +01:00
parent 9f587750eb
commit ab39f741f3
8 changed files with 108 additions and 9 deletions

View File

@ -37,6 +37,16 @@ module.exports = {
return true
}
}
if (msg.activity.type === 'Create')
{
if (msg.object.type === 'Note') {
var content = utils.firstIfArray(msg.object.content)
if (api.me.isFediloveQuiz(content))
await api.me.quizCreate(content, msg.actor.id,
msg.recipient.id, msg.object.id)
return true
}
}
if (msg.activity.type === 'Delete')
{
if (msg.object.type === 'Note') {

View File

@ -14,6 +14,11 @@ module.exports = {
return false
}
},
md5sum: (str, size) => {
size = size || 32
const hasher = crypto.createHmac('md5','FediLove')
return hasher.update(str).digest('hex').slice(0, size)
},
firstIfArray: (o) => {
if (o === undefined)
return null

View File

@ -1,6 +1,6 @@
const api = require('../api-utils.js')
const pwd = require('../passwd.js')
const utils = require('../utils.js')
const random = require('../random.js')
module.exports = {
login: {
@ -16,7 +16,7 @@ module.exports = {
if (!pwd.comparePassword(req.body.password, user.password))
return res.status(403).json({ error: 'invalid_password' })
const session_id = utils.randomString(128)
const session_id = random.base64(128)
const session = await db.table.sessions().insertOne({
id_user: user._id,
session: session_id

View File

@ -1,6 +1,82 @@
const auth = require('../auth.js')
const utils = require('../api-utils.js')
const random = require('../random.js')
function quizParse(html, check) {
check = check === undefined ? false : check
if (html === undefined || html === null)
return false
html = decodeURIComponent(html)
html = html.replaceAll('&gt;','>').replaceAll('&lt;','<')
.replaceAll('&quot;','"').replaceAll('&amp;','&')
html = html.replaceAll(/<br\s+?\/?>/g, '<br>')
html = html.replaceAll('</p>', '\n')
html = html.replaceAll('<br>', '\n')
html = html.replaceAll(/<[^<>]+?>/g, '')
if (!html.toLowerCase().includes('#fedilovequiz'))
return false
if (check)
return true
var it = {}
var sq = false
var items = []
html = html+'\n999: end'
const lines = html.split('\n')
for (var i in lines) {
var ln = lines[i].trim()
if (ln === '')
continue
if (ln.toLowerCase().includes('#fedilovequiz')) {
sq = true
continue
}
if (sq) {
if (ln.match(/^\d+\:.*$/)) {
if (it.question !== undefined)
items.push(it)
ln = ln.substr(ln.indexOf(':')+1)
it = { question: ln.trim(), options: [] }
} else {
ln = ln.replaceAll(/\s?\|\s?/g,'|')
.replaceAll(/\|+/g, '|')
if (!ln.includes('|'))
continue
ps = ln.split('|')
for (var j in ps)
ps[j] = ps[j].trim()
it.options = ps
}
}
}
return items
}
async function quizCreate(content, from, to, replyTo) {
var quiz = quizParse(content)
if (quiz === false)
return false
if (from === undefined || from === null)
return false
if (to === undefined || to === null)
return false
if (replyTo === undefined || replyTo === null)
return false
const payload = {
id: utils.md5sum(replyTo, 16).toUpperCase(),
replyTo, from, to, content: quiz,
}
await db.table.quizs().insertOne(payload)
return payload
}
function isFediloveQuiz(html) {
return quizParse(html, true) !== false
}
module.exports = {
quizParse,
quizCreate,
isFediloveQuiz,
pending_follows: {
get: [auth.enforceSession, async (req, res) => {
let follows

View File

@ -1,5 +1,4 @@
const pwd = require('./passwd.js')
const utils = require('./utils.js')
module.exports = {
enforceSession: async (req, res, next) => {

View File

@ -21,6 +21,7 @@ module.exports = {
objects: () => { return mdb.collection('objects') },
users: () => { return mdb.collection('u__users') },
sessions: () => { return mdb.collection('u__sessions') },
quizs: () => { return mdb.collection('u__quizs') },
},
getAPObject: async (objID, checkType) => {
const object = await module.exports.table

14
api/src/random.js Normal file
View File

@ -0,0 +1,14 @@
const Crypto = require('crypto')
module.exports = {
base64: (size) => {
return Crypto.randomBytes(size)
.toString('base64').slice(0, size)
},
md5: (size) => {
size = size || 32
const rnd = module.exports.base64(32)
const hasher = Crypto.createHmac("md5", rnd.substr(16))
return hasher.update(rnd.substr(0,16)).digest("hex").slice(0, size)
},
}

View File

@ -1,6 +0,0 @@
const Crypto = require('crypto')
exports.randomString = (size) => {
return Crypto.randomBytes(size)
.toString('base64').slice(0, size)
}