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();
/**
* /api/models/Pagans.js
*
* Managed:
/**
* 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,
},
});
});
// @a pi Body {object} schema:pagans /nationchains/schema/pagans.json
/**
* @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: ["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:["pagan"],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 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
* @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 or update a person = alias in tribe. xalias authenticated (in header) must have a profil with accessright into schema person to create a person.
* @apiHeader {string} xhash authenthicate hash with current user keys
* @apiHeader {string} xalias current user
* @apiHeader {string} xprofils profil list
* @apiParam {object} schema:persons https://dnstribe/tribe/schema/persons.json
*
*/
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 (!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 an email or an alias
*
* @apiSuccess {object} send recovery email
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Pagans", "msg":"recoveryemailsent", "data":{email,tribe,nbalias:'number of alias with this email', nbqent:'number of eamil sent must = nbalias'}}
*
* @apiError (404) {string} emailnotfound email does not exist for this tribe
* @apiErrorExample {json}
* {status: 404, ref:"pagans",msg:"emailnotfound",data: { tribe,email } }
*
*/
router.post("/keyrecovery", checkHeaders, (req, res) => {
let emailist=[]
let alias =req.body.search;
if (req.body.emailalias=="email"){
req.body.search=req.body.search.toLowerCase();
const idxreco=`../../${req.body.tribe}/objects/persons/idx/emailrecovery_alias.json`;
if (fs.existsSync(idxreco)){
const emailreco = fs.readJSONSync(idxreco);
const listalias = (emailreco[req.body.search])? emailreco[req.body.search]: [];
listalias.forEach(a=>{
emailist.push({alias:a,tribe:req.body.tribe,lg:req.session.header.xlang})
})
}
}else if (req.body.emailalias=="alias"){
const falias= `../../${req.body.tribe}/objects/persons/itm/${req.body.search}.json`;
if (fs.existsSync(falias)){
emailist.push({alias:req.body.search,tribe:req.body.tribe,lg:req.session.header.xlang})
}
}else{
//console later
}
emailist.forEach(e => {
console.log(e)
const ret= Pagans.sendmailkey(e)
})
if (emailist.length>0) {
res.status(200).json({status:200,ref:"Pagans",msg:"recoveryemailsent",data:{numberemailsent:emailist.length}});
}else{
res.status(404).json({status:404,ref:"Pagans",msg:"recoveryemailnotfound",data:{tribe:req.body.tribe}});
}
});
/**
* @api {get} adminapi/pagans/keyrecovery/:tribe/:alias - recovery keys by alias
* @apiName recoveryKey
* @apiGroup Pagans
* @apiDescription Send to email recovery if exist key files
*
* @apiSuccess {object} send recovery mail for alias
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Pagans", "msg":"recoveryemailsent", "data":{email,tribe,nbalias:1, nbqent:1 or 0}}
*
* @apiError (404) {string} emailnotfound email does not exist for this tribe
* @apiErrorExample {json}
* {status: 404, ref:"pagans",msg:"emailnotfound",data: { tribe,email } }
*
*/
router.get("/keyrecovery/:tribe/:alias", checkHeaders, (req, res) => {
// a tester et revoir
const ret = Pagans.sendmailkey({alias:req.params.alias,tribe:req.params.tribe,lg:req.session.header.xlang})
if (ret.status==200){
return {status:200,ref:"Pagans",msg:"recoveryemailsent",data:{email:"",tribe:req.params.tribe,nbalias:1, nbsent:1}}
}else{
return {status:404,ref:"Pagans",msg:"emailnotfound",data:{tribe:req.params.tribe,email:req.params.email}}
}
});
module.exports = router;