const express = require("express"); const fs = require("fs-extra"); const dayjs = require("dayjs"); const path = require("path"); // Classes const Pagans = require("../models/Pagans.js"); const Odmdb = require("../models/Odmdb.js"); // Middlewares const checkHeaders = require("../middlewares/checkHeaders.js"); const isAuthenticated = require("../middlewares/isAuthenticated.js"); const conf = require(`../../../conf.json`); const currentmod = "pagans"; const log = conf.api.activelog.includes(currentmod); const router = express.Router(); /** * Alias exist then return public key or not * @api {get} adminapi/pagans/alias/:alias - alias Get * @apiName isalias * @apiGroup Pagans * @apiDescription If alias exist return its publickey * * @param {string} alias * * @apiError {json} aliasdoesnotexist * @apiErrorExample {json} * HTTP/1.1 404 Not Found {"status":404,"ref":"pagans","msg":"aliasdoesnotexist","data": { alias}} * * @apiSuccess {object} indexfile content * @apiSuccessExample {json} Success-Response: * HTTP/1.1 200 OK * {"status":200, ref:"pagans","msg":"aliasexist","data": { alias, publicKey }} * * **/ router.get("/alias/:alias", (req, res) => { const getalias = Pagans.getalias(req.params.alias); res.status(getalias.status).send(getalias); }); /** * @api {get} adminapi/pagans/logout - pagan Logout * @apiName Removetoken * @apiGroup Pagans * @apiDescription Remove server's token only the owner of the token (no one else can delete a token ) * * @apiSuccess {object} indexfile content * @apiSuccessExample {json} Success-Response: * HTTP/1.1 200 OK * {status: 200, ref: "Pagans", msg: "logout" * */ router.get("/logout", checkHeaders, isAuthenticated, (req, res) => { if (log) console.log(currentmod, "Logout:", req.session.header); const logout = Pagans.logout( req.session.header.xalias, req.session.header.xtribe, req.session.header.xdays, req.session.header.xhash ); res.status(logout.status).json(logout); }); /** * @api {get} adminapi/pagans/isauth - pagan isAuthenticated? * @apiName isAuth * @apiGroup Pagans * @apiDescription Check if pagan's token is still valid * * @apiError (400) missingheaders * @apiError (400) xaliasdoesnotexist * @apiError (400) signaturefailled * @apiError (401) aliasanonymous * @apiError (404) tribedoesnotexist * * @apiSuccess (200) valid * {object} data contains indexfile requested * */ router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => { res.status(200).send({ status: 200, ref: "headers", msg: "authenticated", data: { xalias: req.session.header.xalias, xprofils: req.session.header.xprofils, }, }); }); /** * @api {post} adminapi/pagans - pagan Post * @apiName addpagan * @apiGroup Pagans * @apiDescription * Create a pagan account from alias, publickey, if trusted recovery => * If trustedtribe is true then create a person in xtribe/person/xalias.json with profil.auth={email,privatekey, passphrase}. * * Middleware isAuthenticated check that: * - xhash is well signed from private key linked to the publickey of alias * - check that alias does not already exist (if yes then verifiedsigne would be false) * Need to wait next block chain to be sure that alias is register in the blokchain * @apiBody {string} alias available (that does not already exist check get /api/alias/:alias that must return 404). * @apiBody {string} publickey * @apiBody {string} [email] if specified then an email is sent to it with public and privatekey * @apiBody {string} [privatekey] * @apiBody {string} [passphrase] if not specidied => passphrase="" * @apiBody {string} [trustedtribe] the tribename if not specified then the process will only create a pagan identity, else an item person is create for trustedtribe (that must exist with profil 'person'). To create a person with an existing pagan identity use put /api/person/:alias after authenticated you (headers). In case a person is created then we use all valid other apiBody respecting the persons schema (see put persons) * * @apiError {json} objectNotfound the file does not exist * @apiErrorExample {json} * HTTP/1.1 404 Not Found {"status":404,"ref":"Odmdb","msg":"pathnamedoesnotexist","data":{indexpath}} * * @apiSuccess {object} indexfile content * @apiSuccessExample {json} Success-Response: * HTTP/1.1 200 OK * {"status":200, "ref":"Odmdb", "msg":"indexexist", "data":{indexname,content:{index file}} * */ router.post("/", checkHeaders, isAuthenticated, async (req, res) => { if (log) console.log(currentmod, "post with", req.body); const role = { xalias: req.session.header.xalias, xprofils: req.session.header.xprofils, }; const emailregex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; if ( !( req.body.trustedtribe && req.body.email && emailregex.test(req.body.email) ) ) { res.status(400).json({ status: 400, ref: "Pagans", msg: "emailerr", data: { email: req.body.email }, }); return; } const objpagan = { alias: req.body.alias, publickey: req.body.publickey }; console.log(path.resolve(`../objects/pagans`)); const newpagan = Odmdb.cud(`../objects/pagans`, "C", objpagan, role); const createprocess = { status: 200, ref: "Pagans", msg: "successfulcreate", data: { alias: req.body.alias }, }; if (newpagan.status == 200) { if (req.body.email) { const emailsent = await Pagans.sendmailkey({ alias: req.body.alias, privatekey: req.body.privatekey, tribe: req.session.header.xtribe, passprhase: req.body.passphrase, publickey: req.body.publickey, email: req.body.email, lg: req.session.header.xlang, }); createprocess.data.emailsent = emailsent.status == 200; createprocess.data.email = req.body.email; createprocess.data.tribe = req.session.header.xtribe; if (emailsent.status != 200) { console.log("pagans err to send email emailsent: ", emailsent); createprocess.data.emailerror = emailsent.data.err; } } if (req.body.trustedtribe) { const persondata = { alias: req.body.alias, owner: req.body.alias, profils: ["anonymous", "pagans", "persons"], recoveryauth: { email: req.body.email, privatekey: req.body.privatekey, publickey: req.body.publickey, passphrase: req.body.passphrase, }, }; const personup = Odmdb.cud( `../../${req.body.trustedtribe}/objects/persons`, "C", persondata, { xprofils: ["anonymous", "pagans"], xalias: req.body.alias } ); if (log) console.log(currentmod, "person create", personup); if (personup.status == 200) { createprocess.data.createperson = true; } else { createprocess.data.createperson = false; createprocess.data.errorperson = true; createprocess.data.errpersonup = personup.data; if (log) console.log( currentmod, "Warning pagan created but person not created and no recovery registration", personup ); } res.status(createprocess.status).json(createprocess); } else { res.status(newpagan.status).json(newpagan); } } else { //error to create pagan certaily already exist res.status(newpagan.status).json(newpagan); } }); /** * @api {delete} adminapi/pagans/alias/:alias - pagan Delete * @apiName deletepagan * @apiGroup Pagans * @apiDescription * Delete an alias and his publickey, this mean that publickey disapear as well as alias. We set dt_delete * */ router.delete("/alias/:alias", checkHeaders, isAuthenticated, (req, res) => { const personpath = `../objects/pagans`; const role = { xalias: req.session.header.xalias, xprofils: req.session.header.xprofils, }; req.session.header.role; const delperson = Odmdb.cud( personpath, "U", { alias: req.params.alias, dt_delete: dayjs().toISOString() }, role, true ); if (log) console.log( currentmod, `DELETE person ${personpath}/${req.params.alias}.json ` ); if (log) console.log(delperson); res.status(delperson.status).json(delperson); if (log) console.log( `DELETE pagans /api/adminapi/objects/pagans/${req.params.alias}.json` ); const result = Pagans.delete(req.params.alias, req.session.header); res.status(result.status).send(result); }); /** * @api {delete} adminapi/pagans/person/:tribe/:alias - person Delete * @apiName deleteperson * @apiGroup Pagans * @apiDescription * Unsubscribe a person to a tribe => remove a person item and all data link to this alias. An asynchrone process turn each day to clean data in tribe, if a persons does not exist anymore in the tribe. Pagans alias is still existing as it is autonomous. It is possible to delete pagans see "pagan Delete". * @apiHeader {array} xprofils list of profil of authenticated user * @apiHeader {string} xalias current user * @apiParam {string} tribe where person alias exist * @apiParam {string} alias to delete as person * */ router.delete( "/person/:tribe/:alias", checkHeaders, isAuthenticated, (req, res) => { const personpath = `../../${req.params.tribe}/objects/persons`; const role = { xalias: req.session.header.xalias, xprofils: req.session.header.xprofils, }; req.session.header.role; const delperson = Odmdb.cud( personpath, "D", { alias: req.params.alias }, role, true ); if (log) console.log( currentmod, `DELETE person ${personpath}/${req.params.alias}.json ` ); if (log) console.log(currentmod, "delete person ", delperson); res.status(delperson.status).json(delperson); } ); /** * @api {get} adminapi/pagans/person/:alias - person Get * @apiName getpersondata * @apiDescription Get person information from his alias for a xtribe (data and profils per apps) * @apiGroup Pagans * * @apiParam {string} alias * * @apiSuccess (200) personExist * @apiSuccessExample {json} * {status:200, ref:"pagans",msg:"personexist",data: { person } } * * @apiError (404) Notfound * @apiErrorExample {json} * {status: 404, ref:"pagans",msg:"persondoesnotexist",data: { person } } * * @todo check accessright for req.session.header.xalias to see if jhe can get person data * if req.param.alias == req.session.header.xalias => Owner * else need accessright to on person set at R * */ router.get("/person/:alias", checkHeaders, isAuthenticated, (req, res) => { console.log( path.resolve(`../../${req.session.header.xtribe}/objects/persons`) ); const getperson = Odmdb.r( `../../${req.session.header.xtribe}/objects/persons`, req.params.alias, { xprofils: req.session.header.xprofils, xalias: req.session.header.xalias } ); res.status(getperson.status).send(getperson); }); /** * @api {put} adminapi/pagans/person/:tribe - person Put * @apiName updateperson * @apiGroup Pagans * @apiDescription add a person = alias in tribe. xalias must be authenticated. This end point have to be use the first time a person is create then use item Update PUT /api/adminapi/odmdb/itm/:tribe/persons.
This endpoint is the only way to change profils of a person by itself (authenitcated alias = person.alias) and can be done only with req.body.addprofils req.body.removeprofils. * @apiHeader {string} xhash authenthicate hash with current user keys * @apiHeader {string} xalias current user * @apiHeader {string} xprofils profil list * @apiParam {string} tribe an existing tribe * @apiBody {object} schema:persons https://dnstribe/tribe/schema/persons.json * @apiBody {string} [addprofils] must be alone no other Body field * @apiBody {string} [removeprofils] must be alone */ router.put("/person/:tribe", checkHeaders, isAuthenticated, (req, res) => { //console.log(req.body); const pathobj = `../../${req.params.tribe}/objects/persons`; const action = fs.existsSync(`${pathobj}/itm/${req.body.alias}.json`) ? "U" : "C"; //set req.body to be in line with schema if ( action == "U" && ((req.body.addprofils && ["seekers", "recruiters", "adminrecruiters"].includes( req.body.addprofils )) || (req.body.removeprofils && ["seekers", "recruiters", "adminrecruiters"].includes( req.body.removeprofils ))) ) { const person = fs.readJsonSync(`${pathobj}/itm/${req.body.alias}.json`); if (!person.profils.includes(req.body.addprofils)) { if (req.body.addprofils) { person.profils.push(req.body.addprofils); } if ( req.body.removeprofils && person.profils.includes(req.body.removeprofils) ) { person.profils = person.profils.filter( (e) => e !== req.body.removeprofils ); Odmdb.cud( `../../${req.params.tribe}/objects/${req.body.removeprofils}`, "D", { alias: req.body.alias }, { xprofils: req.session.header.xprofils, xalias: req.session.header.xalias, } ); } } person.dt_update = dayjs().toISOString(); fs.outputJSONSync(`${pathobj}/itm/${req.body.alias}.json`, person); //console.log(person) res.status(200).json({ status: 200, ref: "Pagans", msg: "profilupdate", data: { alias: person.alias, profils: person.profils }, }); } if (!req.body.addprofils && !req.body.removeprofils) { if (!req.body.profils) { req.body.profils = ["anonymous", "pagans", "persons"]; } const personup = Odmdb.cud(pathobj, action, req.body, { xprofils: req.session.header.xprofils, xalias: req.session.header.xalias, }); if (log) console.log(currentmod, " personupdate or create:", personup); res.status(personup.status).json(personup); } }); /** * @api {post} /adminapi/pagans/keyrecovery - recovery keys * @apiName recoveryKey * @apiGroup Pagans * @apiDescription Send mails with all registers identities (one per alias where recoveryauth.email is register). Search can be request by email or by alias for a tribe. It is looking for in person.recoveryauth.email to send keys. One mail is sent by alias. So if n alias has the same recoveryaut.email then it will send n email. * @apiBody {string} emailalias type of search (email or alias) * @apiBody {string} tribe tribename into looking for * @apiBody {string} search a text containing email or an alias to looking for * * @apiSuccess {object} send recovery email * @apiSuccessExample {json} Success-Response: * HTTP/1.1 200 OK * {"status":200, "ref":"Pagans", "msg":"recoveryemailsent", "data":{email,tribe,numberemailsent'}} * * @apiError (404) {string} recoveryemailnotfound email does not exist for this tribe * @apiErrorExample {json} * {status: 404, ref:"pagans",msg:"recoveryemailnotfound",data: { tribe,email } } * */ router.post("/keyrecovery", checkHeaders, (req, res) => { const recores=Pagans.keyrecovery(req.body.emailalias,req.body.tribe,req.body.search,req.session.header.xlang) res.status(recores.status).json(recores); }); module.exports = router;