diff options
Diffstat (limited to 'generator/postrenderer.js')
-rw-r--r-- | generator/postrenderer.js | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/generator/postrenderer.js b/generator/postrenderer.js new file mode 100644 index 0000000..729c4df --- /dev/null +++ b/generator/postrenderer.js @@ -0,0 +1,161 @@ +module.exports={ + render:function(inf,outf,np,pp){return _render(inf,outf,np,pp);}, + set_template:function(tmplf){return _set_template(tmplf);} +}; +const fs=require('fs'); +const jsdom=require('jsdom'); +const path=require('path'); +const aes=require('aes-js'); +const scrypt=require('scrypt-js'); +const btoa=require('btoa'); +const sha256=require('./sha256').sha256; +const spawn=require('child_process').spawn; +let template_file=''; +let tmplcont=''; +let tocid; +let headerlist; + +function _dfs(doc,el,le,p) +{ + var e=doc.createElement('li'); + e.innerHTML=`<a class="toctarg" href="#tocanch${tocid}">${el.innerHTML}</a>`; + le.appendChild(e); + el.id='tocanch'+(tocid++); + el.classList.add('tvis'); + var che=null,i; + for(i=p+1;i<headerlist.length;) + { + if(headerlist[i].tagName<=el.tagName)break; + if(headerlist[i].classList.contains('notoc'))continue; + if(che===null) + { + var te=doc.createElement('li'); + che=doc.createElement('ul'); + che.classList.add('tocnode'); + te.appendChild(che); + le.appendChild(te); + } + i=_dfs(doc,headerlist[i],che,i); + } + return i; +} +function footnoter(doc) +{ + var footnotes=doc.body.getElementsByTagName("footnote"); + let starting=doc.getElementById("notediv").children.length; + for(var i=0;i<footnotes.length;++i) + { + var s=footnotes[i].innerHTML; + footnotes[i].innerHTML=""; + var a=doc.createElement("a"); + a.setAttribute("id","n"+(starting+i+1)); + a.setAttribute("href","#note"+(starting+i+1)); + a.setAttribute("class","note"); + a.innerHTML="["+(starting+i+1)+"]"; + footnotes[i].parentNode.insertBefore(a,footnotes[i]); + var span=doc.createElement("span"); + span.setAttribute("class","TText"); + span.innerHTML="<a id=\"note"+(starting+i+1)+"\" href=\"#n"+(starting+i+1)+"\">["+(starting+i+1)+"]</a>: "+s+"<br>"; + doc.getElementById("notediv").appendChild(span); + } + starting+=footnotes.length; + while(footnotes.length)footnotes[0].remove(); +} +async function encrypt(doc) +{ + let enid=0; + for(let i of doc.querySelectorAll('encrypted')) + { + const key=i.getAttribute('key'); + i.removeAttribute('key'); + const contu8=aes.utils.utf8.toBytes(i.innerHTML); + const conths=sha256.hash(aes.utils.hex.fromBytes(contu8),{msgFormat:'hex-bytes'}); + const keyu8=aes.utils.utf8.toBytes(key); + const saltu8=aes.utils.utf8.toBytes('hellwhymustiaddsalttothiscrap'); + const enckey=await new Promise( + (resolv,rej)=> + {scrypt(keyu8,saltu8,1024,16,2,32,(e,p,k)=>{e?rej(e):k?resolv(k):undefined;});} + ); + const ctr=new aes.ModeOfOperation.ctr(enckey); + const enccont=ctr.encrypt(contu8); + let encconts='';for(let i=0;i<enccont.length;++i)encconts+=String.fromCharCode(enccont[i]); + encconts=btoa(encconts); + i.setAttribute('hash',conths); + i.setAttribute('encont',encconts); + i.setAttribute('enid',enid); + i.innerHTML= +`This section is encrypted. Click <a href="javascript:void(0)" onclick="decryptui(${enid})">here</a> +to decrypt. <noscript>Note that you need JavaScript enabled for decryption.</noscript>`; + ++enid; + } +} +function _set_template(tmplf) +{ + template_file=tmplf; + tmplcont=fs.readFileSync(template_file,'utf8'); +} +async function _render(inf,outf,np,pp) +{ + const postcont=fs.readFileSync(inf,'utf8'); + const tr=new jsdom.JSDOM(tmplcont); + const trd=tr.window.document; + const cont=fs.readFileSync(inf,'utf8'); + const contsplit=cont.split('\n'); + const meta=contsplit.splice(0,4); + const preproc=meta[3].trim(); + trd.getElementById('title').innerHTML= + trd.getElementById('titleh').innerHTML=meta[0].trim(); + trd.getElementById('datetags').innerHTML=`${meta[1].trim()}<br>#${meta[2].split(',').join(' #')}`; + if(preproc.length) + { + const ppargs=preproc.split(' '); + const ppcmd=ppargs.splice(0,1); + const pp=spawn(ppcmd[0],ppargs,{maxBuffer:1048576}); + let out=''; + pp.stdout.setEncoding('utf8'); + pp.stdout.on('data',(d)=>{out+=d;}); + pp.stdin.write(contsplit.join('\n'),'utf8'); + const ppp=new Promise( + (resolv,rej)=> + { + pp.on('close',(r)=>{if(r)rej(r);resolv(out);}); + } + ); + pp.stdin.end(); + trd.getElementById('article').innerHTML=await ppp; + } + else + trd.getElementById('article').innerHTML=contsplit.join('\n'); + + //Encryption + await encrypt(trd); + + //TOC + const l=trd.getElementById('article').querySelectorAll('h2,h3,h4,h5,h6'); + const tocroot=trd.getElementById('tocroot'); + tocid=0; + headerlist=[]; + for(let i of l) + if(!i.classList.contains('notoc'))headerlist.push(i); + for(let i=0;i<headerlist.length;)i=_dfs(trd,headerlist[i],tocroot,i); + if(!tocroot.children.length)trd.getElementById('tocouter').style.display='none'; + + //Footnotes + footnoter(trd); + + //Tag list + const tgs=meta[2].split(','); + for(let i=0;i<tgs.length;++i) + { + let l=trd.createElement('li'); + l.innerHTML=`<a href="/blog/list/${tgs[i]}/">${tgs[i]}</a>`; + trd.getElementById('tagslist').appendChild(l); + } + + //neighboring posts + if(pp)trd.getElementById('prevp').href=`${pp}.html`; + if(np)trd.getElementById('nextp').href=`${np}.html`; + + fs.writeFileSync(outf,trd.documentElement.outerHTML,'utf8'); + return outf; +} |